我有2个表单 - 第一个表单有一堆编辑,组合框等,第二个表单有一个Web浏览器。
我在第二种形式中有一个例程,它将HTML加载到Webbrowser中,并且在第一个表单上的所有控件的OnChange事件中触发该例程。
问题是,当第二个表单将HTML加载到webbrowser中时,我对第一个表单的集中控制失去了焦点。
如何在例行程序触发时确保第二种形式无法获得焦点?或者更重要的是 - 确保我的第一个表单上的聚焦控件不会失去焦点?
答案 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;
请注意,根据documentation,OnDocumentComplete
可以多次触发。但由于每个呼叫都会收到匹配的用户消息,因此这不是问题。
答案 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上编辑控件中的插入符号。