我在数据库中记录了使用DHtml组件存储为html。但是我想将格式更改为RTF并使用DevExpress TcxRichEdit代替,因为我觉得这是一个更简单的组件,更稳定等。用户有消除文本的问题,我当然无法重现。
TcxRichEdit工作正常,可以再次保存和加载笔记。 问题是html格式的旧笔记。 我试过this routine,但我从来没有让它起作用。 生成了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/ stop命令似乎停止将HTML页面加载到控件中。我偶然使用,因为在另一个地方,它在html中加载数据时可以防止锁定。无论如何,获得转换并摆脱HTML组件真的很棒!
EDIT2: 我终于找到了解决方案而且非常简单。只需在设计时将Dhtml组件添加到表单中,而不是在代码中创建它。这样繁忙的财产是错误的,它只是工作。没有必要在while循环中检查busy,因为这是在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;
感谢您对我的问题的支持和承诺!
答案 0 :(得分:2)
如果您在粘贴之前切割/复制后延迟,则可能有机会。 但总的来说,使用像这样的剪贴板是非常糟糕的做法。提供剪贴板是为了方便用户,而不是程序员。任何能够识别剪贴板的程序都会对此作出反应,包括任何远程桌面/ citrix会话,这些会话都会试图通过网络传播此问题。
答案 1 :(得分:2)
由于这是一次性转换,我和你在一起使用剪贴板。
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。