我有一个专为多个显示器设计的应用程序。它启动了,我们试图避免激活不需要激活的窗口,因为用户只在一个地方进行键盘输入,每次我们在辅助监视器上激活一个新表单时,它会抓住键盘焦点,这是我们的事情。希望避免。
我们的内部基础TForm类有一个这样的方法,它直接使用Win32 ShowWindow函数,避免了VCL框架的内部可见性变化系统,它抓住了焦点:
procedure TOurForm.ShowWithoutActivate;
begin
ShowWindow(Self.Handle, SW_SHOWNOACTIVATE);
Self.Visible := true;
end;
如果我这样做,它会抓住焦点:
Self.Visible := true; // TWindow.Visible = true, will grab focus, plus make window visible.
这样可行,但接下来我想做的就是设置最大化状态,以便 表格将在目前正在使用的监视器上最大化。我们如何将它放到特定的显示器上?通过修改Form的Left和Top属性,它始终以相同的方式工作。我们必须注意,如果我们在表单上存储Left / Top / Width / Height,然后将其恢复,那么当我们重新加载它时结果仍然有效。这不是我要问的问题。
我特别询问如何最大化表格现在我已经"显示"它使用上面的自定义功能。一个黑客攻击另一个黑客。这是我离开这个兔子洞的距离:
是否有可能使这个表单可见并使其处于我想要的窗口状态而不激活?如果我不能这样做,那么当我在辅助显示器上显示此表单时,用户将失去键盘焦点,这是我真正想要避免的。
我尝试使用Win32 ShowWindow
API执行SW_SHOWMAXIMIZED
:
ShowWindow(Self.Handle, SW_SHOWMAXIMIZED);
以上似乎抓住焦点(激活)。
答案 0 :(得分:6)
创建顶级窗口时,将扩展窗口样式设置为
WS_EX_NOACTIVATE | WS_EX_APPWINDOW
WS_EX_NOACTIVATE
停止激活窗口。这也使它从任务栏中消失,因此您需要WS_EX_APPWINDOW
来解决该问题。
调用ShowWindow(hWnd, SW_MAXIMIZE)
,窗口将最大化但未激活。
您需要能够在窗口可见时激活窗口,因此在WM_ACTIVATE
处理程序(具有讽刺意味!)中,您需要清除WS_EX_NOACTIVATE
标志:
case WM_ACTIVATE:
{
DWORD exstyle = GetWindowLong(hWnd, GWL_EXSTYLE);
if (exstyle & WS_EX_NOACTIVATE)
{
SetWindowLong(hWnd, GWL_EXSTYLE, exstyle & ~(DWORD)WS_EX_NOACTIVATE);
}
}
为C ++道歉。这应该很容易转换成Delphi。
答案 1 :(得分:4)
EnumDisplayMonitors
API枚举联合桌面上的监视器及其坐标,特定监视器映射到其特定位置的区域。
要找出哪个监视器是“当前”,您需要将当前窗口位置与监视器坐标rcMonitor
/ rcWork
进行比较。或者,您有MonitorFromPoint
和朋友帮助您。
一旦确定了您想要的监视器,您可以将窗口(MoveWindow
,SetWindowPos
)移动到监视器的工作区域,或者使用此矩形来响应要发送的WM_GETMINMAXINFO
消息作为标准最大化的一部分,这个位置的窗口。