23

在多显示器系统上,“空白”VCL 应用程序可以很好地最大化,但是启用样式(并且选择了一个作为默认样式)的同一应用程序会错误地最大化。我看到的是窗口的右侧边缘延伸到第二台显示器(我的主要在左侧)。当我开始与其他 Windows 应用程序进行比较时,我注意到在 Windows 7 下(至少),最大化的窗口甚至在左侧、右侧或底部都没有非客户端边框。事实上,标准 VCL(非样式化)应用程序的行为方式相同,没有非客户端边界。

我该如何解决?我注意到 TFormStyleHook 有一个 WMNCCalcSize 处理程序,我还没有剖析它,但让我想知道 VCL 是否可能错误地处理最大化窗口的此消息。

4

2 回答 2

5

在摆弄了一些时间之后,我的看法是,这根本不是 vcl 样式的错误。这确实与mghie对问题的评论中提到的文章中的行为有关。

具体行为是,最大化窗口的大小大于窗口最大化的监视器的工作区域。据说,窗口管理器隐藏了悬垂的边框。显然,对于定制的框架,它并没有做到这一点。请注意,MSDN 自己的自定义窗口框架示例似乎遇到了同样的问题(请参阅社区内容中标题为“窗口最大化时的错误”的帖子)。VCL 的应用程序与 MSDN 示例的不同之处在于它不是基于 DWM,但我仍然认为这是同一个问题。

悬垂边界的大小与系统调整边界 (SM_C[X|Y]SIZEFRAME) 的大小相同,但这与下面的解决方法无关,因为它忽略了操作系统建议的大小/位置并使用了工作区。

不幸的是,我认为这种解决方法根本不可用。一方面,没有记录提到的行为,另一方面,解决方法并不完美;仍然有一个奇怪的像素。如果您将窗口准确地捕捉到工作区,窗口管理器会决定将窗口偏移到它认为应该放置窗口(带有隐藏框架)的位置。(VCL 可能会被修改为执行窗口管理器所做的事情,并考虑到悬垂并且不绘制它们或类似的东西,但这将是更多的工作,它仍然是解决未记录的行为..)

反正;

type
  TForm1 = class(TForm)
    ..
  protected
    // overriding styles is not necessary since TFormStyleHook.WMGetMinMaxInfo
    // first calls the default window procedure 
    procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
      message WM_GETMINMAXINFO;

..

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
var
  R: TRect;
begin
  // always arrives with MinMaxInfo.ptMaxPosition = (-SM_CXFRAME, -SM_CYFRAME)
  // and MinMaxInfo.ptMaxSize = (PrimaryMonitor.Width (?) + 2 * SM_CXFRAME, ... )
  inherited;

  // should test for OS, styles etc. before running the below 
  R := Monitor.WorkareaRect;
  InflateRect(R, -1, -1);             // odd pixel
  OffsetRect(R, -Monitor.Left, -Monitor.Top);
  Message.MinMaxInfo.ptMaxPosition := R.TopLeft;
  Message.MinMaxInfo.ptMaxSize := Point(R.Width, R.Height);
end;
于 2012-08-02T02:16:10.970 回答
1

我发现的唯一方法是处理 WM_SIZE 事件并修改窗口区域以切断额外的边框。

于 2013-10-14T22:28:40.520 回答