我对 Delphi 和 WebBrowser 组件感到疯狂。
我创建了一个简单的应用程序,用于在备忘录中输入 HTML 并在 WebBrowser 组件中显示结果。
但是,当我在 WebBrowser 内部单击时,每个 HTML 代码更新(在备忘录中)都会导致 WebBrowser 组件窃取焦点。
以下是重现问题的步骤:
在 Memo1.OnChange 事件上插入:
if WebBrowser1.Document = nil then
begin
WebBrowser1.Navigate('about:blank');
while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
end;
ms := TMemoryStream.Create;
try
Memo1.Lines.SaveToStream(ms);
ms.Seek(0, 0);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(ms)) ;
finally
ms.Free;
end;
运行应用程序
在备忘录中输入 HTML
<html>
<body>
Hello WebBrowser
</body>
</html>
在网络浏览器内容中单击
如何解决这个问题并防止“窃取焦点”?
Ps.:唯一的解决方法是在网页浏览器上点击后按TAB键,这可以防止网页浏览器在通过备忘录对html代码进行新更改后窃取焦点。
通过此解决方法解决了。
将 Memo1.OnChange 代码更改为:
procedure TForm1.Memo1Change(Sender: TObject);
var
ms: TMemoryStream;
begin
LockWindowUpdate(panel1.Handle); // fix: lock webbrowser parent updates
// fix: re-set the webbrowser parent to prevent focus stealing
TControl(WebBrowser1).Parent := nil;
TControl(WebBrowser1).Parent := panel1;
// fix:eof
if WebBrowser1.Document = nil then
begin
WebBrowser1.Navigate('about:blank');
while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
end;
ms := TMemoryStream.Create;
try
Memo1.Lines.SaveToStream(ms);
ms.Seek(0, 0);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(ms)) ;
finally
ms.Free;
end;
LockWindowUpdate(0); // fix: unlock webbrowser parent updates to prevent flicking!!
end;
我意识到我用 Memo2 所做的事情与你所做的并不完全相同,但是 可能更可取,因为备忘录不需要包含外部结构 HTML 文档的。根据您正在做的事情,这可能是一个优势 或缺点。
Fwiw,单击 WB 后调用 ShowCaret(Memo1.Handle) 返回 false - GetLastError/SysErrorMsg 报告 5/访问被拒绝,所以我猜测单击 WB 会以某种方式破坏 Memo1 的插入符 - 我的意思是比您预期的要多只是从转移焦点。我还在研究这个问题。
procedure TForm1.Memo1Change(Sender: TObject);
var
ms : TMemoryStream;
begin
if WebBrowser1.Document = nil then
begin
WebBrowser1.Navigate('about:blank');
while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
end;
try
if CheckBox1.Checked then begin
(WebBrowser1.Document as IHtmlDocument2).Body.innerHtml := Memo2.Lines.Text;
end
else begin
ms := TMemoryStream.Create;
try
Memo1.Lines.SaveToStream(ms);
ms.Seek(0, 0);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(ms)) ;
finally
ms.Free;
end;
end;
except
// silence any exceptions raised when using CheckBox1.Checked = True
end;
end;
更新:
如果您希望比我上面的建议更接近您的原始内容,请使用以下内容 更紧凑,似乎运行得更快一些:
procedure TForm1.HandleMemo1ChangeNew(Sender : TObject);
var
Doc : IHtmlDocument2;
V : OleVariant;
begin
if WebBrowser1.Document = nil then
WebBrowser1.Navigate('about:blank');
Doc := WebBrowser1.Document as IHTMLDocument2;
V := VarArrayCreate([0, 0], varVariant);
V[0] := Memo1.Lines.Text;
Doc.Write(PSafeArray(TVarData(v).VArray));
Doc.Close;
end;
procedure TForm1.WebBrowser1NavigateComplete2(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
begin
WebBrowser1.Enabled := False;
end;
✅向 WEBBrowser 表单添加一个 TButton 和一个 TEdit。
✅将这些组件留在表单的可见区域之外,为两者的 Top 属性分配负值(保持属性 Visible=True)。
✅在Button的OnClick事件中添加: 编辑1.设置焦点; Edit1.Text:=DateTimeToStr(Now);
✅在WebBrowser的CommandStateChange事件中,添加: 工具按钮1.单击;