确保在运行例程时Form不会获得焦点

时间:2011-07-15 17:59:41

标签: forms delphi focus vcl

我有2个表单 - 第一个表单有一堆编辑,组合框等,第二个表单有一个Web浏览器。

我在第二种形式中有一个例程,它将HTML加载到Webbrowser中,并且在第一个表单上的所有控件的OnChange事件中触发该例程。

问题是,当第二个表单将HTML加载到webbrowser中时,我对第一个表单的集中控制失去了焦点。

如何在例行程序触发时确保第二种形式无法获得焦点?或者更重要的是 - 确保我的第一个表单上的聚焦控件不会失去焦点?

3 个答案:

答案 0 :(得分:2)

一个简单的解决方案是禁用包含Web浏览器控件的表单。禁用的窗口无法获得焦点。

当触发TWebControl的OnDocumentComplete事件时,浏览器控件已准备好获得焦点。在此处停用表单,并发布消息,以便您可以很快启用该表单:

const
  UM_POSTENABLE = WM_USER + 12;

type
  TForm2 = class(TForm)
    WebBrowser1: TWebBrowser;
    procedure WebBrowser1DocumentComplete(ASender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
  private
    procedure UMPostEnable(var Msg: TMessage); message UM_POSTENABLE;
  end;

var
  Form2: TForm2;

implementation

uses Unit1;

{$R *.dfm}

procedure TForm2.WebBrowser1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
begin
  if Screen.ActiveForm = Form1 then begin
    Enabled := False;
    PostMessage(Handle, UM_POSTENABLE, 0, 0);
  end;
end;

procedure TForm2.UMPostEnable(var Msg: TMessage);
begin
  Enabled := True;
end;

请注意,根据documentationOnDocumentComplete可以多次触发。但由于每个呼叫都会收到匹配的用户消息,因此这不是问题。

答案 1 :(得分:2)

你要做的事情与VCL相反,可能违背了普通的用户期望:当显示一个新窗口时,除非它是一个工具窗口,通常(和预期的)行为是将焦点移到它上面。显示窗口的Win32 Api为ShowWindow并且它将激活窗口,除非指定了SW_SHOWNOACTIVATE标志(或其中一个变体)。

当您显示VCL表单时,也会调用该函数。对ShowWindow的调用隐藏在procedure TCustomForm.CMShowingChanged(var Message: TMessage)中,这是一个135行程序,用于对SW_SHOWNORMAL标记进行硬编码(即:激活标记),用于调用VCL的ShowWindow让。不幸的是,这是一大段代码并且压倒它并不容易。如果这是我的程序,我可能会尝试更改代码:我会向DoNotActivate:Boolean添加TCustomForm标志并更改{{1}中的单行代码1}}为非MDI表单调用CMShowingChanged来考虑该标记并简单地调用ShowWindow。如果改变VCL并不是一件轻松的话,你可以使用以下hacky解决方案:

我建议的诀窍是创建新表单(持有ShowWindow(Handle, SW_SHOWNOACTIVATE)的表单),但不要将TWebBrowser属性设置为Visible。而是,手动调用True)以显示表单而不激活它。因为此代码不再通过通常的Delphi VCL进行编码,所以不会自动创建和显示所拥有的控件,因此需要递归地ShowWindow(Handle, SW_SHOWNOACTIVATE调用,对于表单的所有ShowWindow(...)后代: / p>

TWinControl

此代码还有一个问题:确保导航到没有自动聚焦的表单的网页。导航到microsoft的MSDN库对于代码示例可能不常见,但该规范示例(www.google.com)将焦点设置为搜索表单。

答案 2 :(得分:1)

procedure TForm1.FormCreate(Sender: TObject);
begin
  Screen.OnActiveFormChange := ActiveFormChanged;
end;

procedure TForm1.ActiveFormChanged(Sender: TObject);
begin
  if not (csDestroying in ComponentState) then
    if ActiveControl <> nil then
      ActiveControl.SetFocus
end;

procedure TForm1.EditOrComboChange(Sender: TObject);
begin
  Form2.WebBrowser.SetFocus;
end;

修改

也许这不是最优雅的方式。作为替代方案,我试过

Form2.WebBrowser.Enabled := False;

完全避免焦点交换。这使得焦点集中在编辑控件上,奇怪的是,禁用的WebBrowser会更新到新页面,但更神秘的是,这会隐藏Form1上编辑控件中的插入符号。