如何使表单可见并最大化以填充辅助监视器而不激活它?

时间:2013-12-12 16:06:11

标签: delphi winapi delphi-xe2

我有一个专为多个显示器设计的应用程序。它启动了,我们试图避免激活不需要激活的窗口,因为用户只在一个地方进行键盘输入,每次我们在辅助监视器上激活一个新表单时,它会抓住键盘焦点,这是我们的事情。希望避免。

我们的内部基础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,然后将其恢复,那么当我们重新加载它时结果仍然有效。这不是我要问的问题。

我特别询问如何最大化表格现在我已经"显示"它使用上面的自定义功能。一个黑客攻击另一个黑客。这是我离开这个兔子洞的距离:

  • 当TForm(也是TWinControl的私有字段FShowing)为假时,设置Form.Maximized无效。
  • 当TForm的TWinControl.FShowing字段设置为true时,将windowState设置为wsMaximized也会导致表单激活。

是否有可能使这个表单可见并使其处于我想要的窗口状态而不激活?如果我不能这样做,那么当我在辅助显示器上显示此表单时,用户将失去键盘焦点,这是我真正想要避免的。

我尝试使用Win32 ShowWindow API执行SW_SHOWMAXIMIZED

  ShowWindow(Self.Handle, SW_SHOWMAXIMIZED);

以上似乎抓住焦点(激活)。

2 个答案:

答案 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和朋友帮助您。

一旦确定了您想要的监视器,您可以将窗口(MoveWindowSetWindowPos)移动到监视器的工作区域,或者使用此矩形来响应要发送的WM_GETMINMAXINFO消息作为标准最大化的一部分,这个位置的窗口。

除此之外,这个小型C ++应用程序[123]演示了上述概念,显示了监视器信息,并更改了窗口最大化的位置到。