确保例程运行时表单不会获得焦点
我有 2 个表单 - 第一个表单有一堆编辑、组合框等,第二个表单有一个 Web 浏览器。
我在第二个表单中有一个例程,它将 HTML 加载到 Web 浏览器中,并且该例程在第一个表单上的所有控件的 OnChange 事件中触发。
问题是,当第二个表单将 HTML 加载到网络浏览器时,我对第一个表单的集中控制失去了焦点。
如何确保例程触发时第二种形式不会获得焦点?或者,更重要的是 - 确保我的第一个表单上的聚焦控件不会失去焦点?
I have 2 forms - The first form has a bunch of edits, comboboxes, etc, and the 2nd form has a Webbrowser.
I have a routine in the 2nd form, that loads HTML into the Webbrowser, and that routine is fired in the OnChange event of all my controls on the first form.
The problem is, that my focused control on my first form looses focus, when the 2nd form is loading the HTML into the webbrowser.
How can I make sure that the 2nd form does not get focus when the routine is fired? Or, more importantly - make sure that the focused control on my first form, does not loose focus?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您尝试做的事情违背了 VCL,并且可能违背了通常的用户期望:当显示新窗口时,除非它是工具窗口,否则通常(和预期)的行为是将焦点移至它。显示窗口的 Win32 Api 是 ShowWindow 并且它将激活窗口,除非指定了 SW_SHOWNOACTIVATE 标志(或其变体之一)。
当您使 VCL 窗体可见时,也会调用该函数。对
ShowWindow
的调用隐藏在procedure TCustomForm.CMShowingChanged(var Message: TMessage)
中,这是一个 135 行的过程,对SW_SHOWNORMAL
标志进行硬编码(即:激活标志)用于 VCL 进行的ShowWindow
调用。不幸的是,这是一大段代码,覆盖它并不容易。如果这是我的程序,我可能会尝试更改代码:我会向TCustomForm
添加一个DoNotActivate:Boolean
标志并更改CMShowingChanged
中的单行代码调用非 MDI 表单的ShowWindow
来考虑该标志,只需调用ShowWindow(Handle, SW_SHOWNOACTIVATE)
。如果更改 VCL 不是一件轻松的事情,您可以使用以下 hacky 解决方案:我建议的技巧是创建新表单(包含
TWebBrowser
的表单),但是不要将其Visible
属性设置为True
。相反,手动调用 ShowWindow(Handle, SW_SHOWNOACTIVATE) 来显示表单而不激活它。由于此代码将不再通过通常的 Delphi VCL 进行编码,因此不会自动创建和显示拥有的控件,因此需要对所有递归调用
后代:ShowWindow(...)
表单的 TWinControl此代码还有一个问题:确保导航到的网页没有自动聚焦的表单。对于代码示例来说,导航到 Microsoft 的 MSDN 库可能不太常见,但该规范示例 (www.google.com) 将焦点设置在搜索表单上。
What you're trying to do goes against the VCL, and probably goes against usual user expectations: When a new window is shown, unless it's a tool window, the usual (and expected) behavior is to move focus to it. The Win32 Api to show a window is ShowWindow and it'll activate the window, unless the
SW_SHOWNOACTIVATE
flag (or one of it's variants) is specified.When you make a VCL form visible, a call to that function is also made. The call to
ShowWindow
is buried inprocedure TCustomForm.CMShowingChanged(var Message: TMessage)
, a 135 lines procedure that hard-codes theSW_SHOWNORMAL
flag (ie: an Activating flag) for theShowWindow
call that the VCL makes. Unfortunately that's a big piece of code and overriding it is not going to be easy. If this was my program I'd probably attempt changing the code in place: I'd add aDoNotActivate:Boolean
flag toTCustomForm
and change the single line of code inCMShowingChanged
that callsShowWindow
for non-MDI forms to take that flag into account and simply callShowWindow(Handle, SW_SHOWNOACTIVATE)
. If changing the VCL is not something you'd do light-hearted, you can use the following hacky solution:The trick I'm suggesting is to create the new form (the one holding
TWebBrowser
) but do NOT set it'sVisible
property toTrue
. Instead, make manual calls toShowWindow(Handle, SW_SHOWNOACTIVATE
) to show the form without activating it. Because this code would no longer code through the usual Delphi VCL, owned controls would not automatically be created and shown, so theShowWindow(...)
call needs to be made recursively, for allTWinControl
descendants of the form:There's an other catch with this code: Make sure you navigate to a web page that doesn't have a form that's automatically focused. Navigating to microsoft's MSDN library might be unusual for a code sample, but that canonical example (www.google.com) sets focus to the search form.
一种简单的解决方案是禁用包含 Web 浏览器控件的表单。禁用的窗口将不会获得焦点。
当 TWebControl 的 OnDocumentComplete 事件被触发时,浏览器控件就准备好获得焦点。禁用此处的表单,并向自己发布一条消息,以便您可以尽快启用该表单:
请注意,根据 文档,
OnDocumentComplete
可以多次触发。但由于每次调用都会收到匹配的用户消息,因此这不会成为问题。One simple solution can be to disable the form containing the web browser control. A disabled window will not gain the focus.
When the
OnDocumentComplete
event of TWebControl is fired, the browser control is ready to gain focus. Disable the form here, and post yourself a message so that you can enable the form shortly:Note that, according to the documentation,
OnDocumentComplete
can be fired multiple times. But since each call will receive a matching user message, this wouldn't be a problem.编辑
也许这不是最优雅的方式。作为替代方案,我尝试使用
Form2.WebBrowser.Enabled := False;
来完全阻止焦点交换。这使焦点保持在编辑控件上,奇怪的是禁用的 WebBrowser 会更新到新页面,但更神秘的是,这隐藏了 Form1 上编辑控件中的插入符号。
Edit
Maybe this is not the most elegant way. As an alternative I tried
Form2.WebBrowser.Enabled := False;
to prevent the focus exchange at all. This keeps the focus on the edit control and strangely enough does the disabled WebBrowser update to the new page, but more mysteriously, this hides the caret in the edit control on Form1.