如何防止delphi TWebBrowser窃取焦点

问题描述 投票:0回答:2

我对 Delphi 和 WebBrowser 组件感到疯狂。

我创建了一个简单的应用程序,用于在备忘录中输入 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>
    
  • 在网络浏览器内容中单击

  • 返回备忘录并尝试在 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;
    
delphi focus webbrowser-control twebbrowser
2个回答
1
投票
将一个复选框和另一个备忘录 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;
    

0
投票
我发现解决这种情况的唯一方法是采用以下解决方案:

✅向 WEBBrowser 表单添加一个 TButton 和一个 TEdit。

✅将这些组件留在表单的可见区域之外,为两者的 Top 属性分配负值(保持属性 Visible=True)。

✅在Button的OnClick事件中添加: 编辑1.设置焦点; Edit1.Text:=DateTimeToStr(Now);

✅在WebBrowser的CommandStateChange事件中,添加: 工具按钮1.单击;

© www.soinside.com 2019 - 2024. All rights reserved.