У меня есть записи в базе данных, хранящиеся как html с компонентом DHtml. Но я хочу изменить формат RTF и использовать DevExpress TcxRichEdit вместо этого, потому что я чувствую, что это более простой компонент, более стабильный и т.д. У пользователей возникают проблемы с исчезающими текстами, которые я, конечно, не могу воспроизвести.
TcxRichEdit работает нормально и может сохранять и загружать заметки снова. Проблема заключается в старых заметках в формате html. Я пробовал эту процедуру, но я так и не получил ее на работу. Строка rtf была сгенерирована, но она не была принята TcxRichEdit.
Тогда у меня появилась идея использовать буфер обмена. Имея DHTML и TcxRichEdit бок о бок, я должен копировать и вставлять между ними, и пусть буфера обмена выполняет фактическое преобразование. На практике это было не так просто, как я думал...
Вот какой код:
function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Boolean;
begin
Result := False;
if (aHtml <> '') and (aHtml <> ' ') then
begin
if not AnsiStartsStr('{\rtf1', aHtml) then
begin
vHtmlDlg.InitDoc := aHtml;
vHtmlDlg.Editor.Stop;
if vHtmlDlg.Editor.SelectAll then
if vHtmlDlg.Editor.CutToClipboard then
begin
aRichEdit.Clear;
aRichEdit.PasteFromClipboard;
end;
end;
Result := True;
end;
end;
Проблема в том, что vHtmlDlg.Editor.SelectAll всегда возвращает False.
function TCustomProfDHTMLEdit.SelectAll: Boolean;
const
CGID_MSHTML: TGUID = '{DE4BA900-59CA-11CF-9592-444553540000}';
var
D: IDispatch;
CommandTarget: IOleCommandTarget;
vaIn, vaOut: OleVariant;
hr: HRESULT;
begin
Result := False;
if GetDOM(D) then
try
CommandTarget := D as IOleCommandTarget;
hr := CommandTarget.Exec(@CGID_MSHTML, 31, OLECMDEXECOPT_DODEFAULT, vaIn, vaOut);
Result := SUCCEEDED(hr)
except
end
end;
Это фактически GetDOM, который возвращает False:
function TProfDHTMLEdit2.GetDOM(out P: IDispatch): Boolean;
begin
if Busy then
begin
P := nil;
Result := False
end
else
try
P := (IDispatch(GetOleObject) as IWebBrowser2).Document;
Result := True
except
P := nil;
Result := False
end
end;
Нет, это GetBusy, который возвращает true...
function TProfDHTMLEdit2.GetBusy: Boolean;
begin
if FDocumentCompleteReason <> dcrUndefined then
Result := True
else
Result := False
end;
Итак, я пробовал глубже и глубже копать в компоненте html, но я до сих пор не понимаю, почему я не могу использовать SelectAll.
Вот упрощенная версия того, как я инициализирую и использую ее.
vHtmlDlg := TDhtmlEditorForm.Create(nil);
vHtmlDlg.Show;
vHtmlDlg.BrowseMode := False;
try
// Call ConvertToRtf with strings in a loop here
finally
vHtmlDlg.Free;
end;
Любая идея, почему SelectAll возвращает false и не работает?
Edit1: Еще кое-что. Документы для компонента html находятся здесь http://www.profgrid.com/documentation/htmledit/ Команда остановки, похоже, перестает загружать HTML-страницу в элемент управления. Я использовал случайно, потому что в другом месте он предотвращает блокировку при загрузке данных в html. В любом случае было бы очень приятно получить преобразование и избавиться от HTML-компонента!
Edit2: Я нашел решение наконец, и это было довольно просто. Просто добавьте компонент Dhtml в форму во время разработки вместо того, чтобы создавать его в коде. Таким образом, занятое свойство было ложным, и оно просто работает. Нет необходимости проверять занятость в цикле while, как это делается в методе SetSource. Я даю jachquate галочку, поскольку он отмечает меня, что компонент был асинхронизирован. Окончательный код для преобразования строки выглядит следующим образом:
function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Integer;
begin
if (aHtml <> '') and (aHtml <> ' ') then
begin
if not AnsiStartsStr('{\rtf1', aHtml) then
begin
DhtmlMemo.Source := aHtml;
if DhtmlMemo.SelectAll then
if DhtmlMemo.CutToClipboard then
begin
aRichEdit.Clear;
aRichEdit.PasteFromClipboard;
end;
if VarIsNull(aRichEdit.EditValue) then
Result := 0 // Not valid. The caller would delete the note.
else
Result := 2; // String was converted
end
else
Result := 1; // String already in rtf. Do nothing.
end
else
Result := 0;
end;
Спасибо за поддержку и приверженность моей проблеме!
Поскольку это одноразовое преобразование, я с вами в отношении использования буфера обмена.
Компонент HTML выглядит как некий компонент Async, поэтому вам придется ждать, потому что он будет обрабатывать загрузку/представление предоставленного HTML в других потоках, все инкапсулируется компонентом. Я не знаю конкретного компонента, но я уверен, что это сработает:
function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Boolean;
begin
Result := False;
if (aHtml <> '') and (aHtml <> ' ') then
begin
if not AnsiStartsStr('{\rtf1', aHtml) then
begin
vHtmlDlg.InitDoc := aHtml;
vHtmlDlg.Editor.Stop;
//before or after stop, I'm not sure what stop means
while vHtmlDlg.Busy do
Sleep(1); // or maybe Application.ProcessMessages, try both
if vHtmlDlg.Editor.SelectAll then
if vHtmlDlg.Editor.CutToClipboard then
begin
aRichEdit.Clear;
aRichEdit.PasteFromClipboard;
Result := True; //of course you return true only if this succeeds.
end;
end;
end;
end;
Если это многократное преобразование, которое должно выполняться на пользовательской машине, прочитайте @Chris answer.
У вас может быть шанс, если вы положите задержку после вырезания/копирования перед пастой. Но в целом использование такого буфера обмена очень плохое. Буфер обмена предоставляется для удобства пользователя, а не для программиста. Любые программы, ориентированные на буфер обмена, будут реагировать на это, включая любые сеансы удаленного рабочего стола /citrix, которые будут пытаться перекачивать эту информацию по сети.