当前位置 : 主页 > 编程语言 > delphi >

如何防止delphi TWebBrowser窃取焦点

来源:互联网 收集:自由互联 发布时间:2021-06-23
我对Delphi和WebBrowser组件感到很疯狂. 我创建了一个简单的应用程序,在Memo中键入HTML并在WebBrowser组件中显示结果. 但是,当我在WebBrowser中单击时,每个HTML代码更新(在备忘录中)都会导致Web
我对Delphi和WebBrowser组件感到很疯狂.

我创建了一个简单的应用程序,在Memo中键入HTML并在WebBrowser组件中显示结果.

但是,当我在WebBrowser中单击时,每个HTML代码更新(在备忘录中)都会导致WebBrowser组件窃取焦点.

以下是重现问题的逐步步骤:

>创建一个新的VCL应用程序
>添加一个TWebBrowser组件来显示html
>添加TMemo组件以键入html代码
>在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>

>在WebBrowser内容中单击
>返回备忘录并尝试在HTML中输入更多更改
>在这里我们去*,在每个按键上,webbrowser组件窃取它的焦点!

我怎样才能解决这个问题并防止“窃取焦点”?

Ps.:唯一的解决方法是在点击WebBrowser后按TAB键,这可以防止webbrowser在通过备忘录对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,并将其OnChange指向
你的Memo1的处理程序.然后,更改您的处理程序,如下所示.你应该找到
即使在使用Memo1引发焦点窃取之后,当你输入时也不会发生这种情况
Memo2(当然选中了复选框).

我意识到我用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;
网友评论