如何删除wsNormal全屏表单标题栏内容偏移量?

时间:2016-08-10 23:05:55

标签: delphi windows-10 vcl titlebar

通过WindowState:= wsMaximized最大化表单时,标题栏如下所示:

Maximized form with a "normal" title bar

将窗体设置为WindowState:= wsNormal并将窗体大小设置为全屏状态时,框架内容相同但标题栏稍有移动。

enter image description here

800 * 600屏幕上的wsNormal表单矩形模拟wsMaxed表格是TRect(-8,-8,808,608)。 (见this question why the difference of the size is necessary

我的问题: 如何修复wsNormal窗口中移动的标题栏内容,以便它看起来像下面的模拟一样正确?

enter image description here

带有一个按钮的简单示例表单,可以再现两种表单状态。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FState: Integer;
  public
    { Public-Deklarationen }
    procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  LBRect: TRect;
begin
  LBRect  := Screen.Monitors[0].BoundsRect;

  case FState of
    0:
    begin
      WindowState := wsMaximized;
    end;
    1:
    begin
      WindowState := wsNormal;
      LBRect := Screen.Monitors[0].WorkareaRect;
      LBRect.Inflate(8,8); //offset 8 for a form with bsSizeable
      BoundsRect := LBRect;
    end;
  end;

  Inc(FState);
  FState := FState mod 2;
end;

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
begin
  //slightly smaller MaxTrackSize would prevent the wsNormal form the fully cover the screen on the right side
  Message.MinMaxInfo.ptMaxTrackSize := Message.MinMaxInfo.ptMaxSize;
end;

end.

EDIT1:

澄清为什么这可能有用: 我们有一个多显示器设置,具有相同的分辨率屏幕,并希望跨越这个非常大的虚拟屏幕。桌面不能通过例如一个大屏幕统一到一个大屏幕。 AMD的Virtual Destkop设置。

出现此问题是因为最大化表单的标题栏rect的高度略小于非最大化表单标题栏的高度。

此外,需要负位置和放大尺寸,caused by the (backwards compatible) way windows handles the border calculations and positioning.实际偏移/放大来自所选择的边界风格。

2 个答案:

答案 0 :(得分:2)

经过一些研究,我找到了一种方法,以最小的努力达到所描述的场景的目标。这不会回答问题本身,只会达到目标。

创建表单时以及最大化表单时(通过用户或将表单WindowState设置为wsMaximized),窗口消息WM_GETMINMAXINFO将被发送。

发送WM_GETMINMAXINFO后,系统会在最大化的情况下询问表单的所需位置和大小。

在这里,我们可以覆盖Windows默认定位,例如通过相应地设置值,跨越多个屏幕的最大化视图。

分析通过WM_GETMINMAXINFO消息发送的默认值时,每个维度的值偏移量为8。

The offset was necessary on older Windows OS告诉窗口管理器隐藏当前屏幕视图之外的bordertyle,并且还会导致edge bleeding on multi-monitor setup。 当WindowState被设置为wsNormal时,边缘出血也会发生。

Offset还会告诉Windows窗口管理器在停靠到顶部时减少标题栏大小并正确呈现标题栏内容(这是我们搜索的目标)。 / p>

请参阅以下示例:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FState: Integer;
  public
    { Public-Deklarationen }
    procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  case FState of
    0:
    begin
      WindowState := wsMaximized;
    end;
    1:
    begin
      WindowState := wsNormal;
      BoundsRect := TRect.Create(100,-8,300,192);
    end;
    2:
    begin
      WindowState := wsMaximized;
    end;
    3:
    begin
      WindowState := wsNormal;
      BoundsRect := TRect.Create(100,0,300,200);
    end;
    4:
    begin
      WindowState := wsMaximized;
    end;
    5:
    begin
      WindowState := wsNormal;
      BoundsRect := TRect.Create(100,100,300,300);
    end;
  end;

  Inc(FState);
  FState := FState mod 6;
end;

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
begin
case FState of
  0, 1:
  begin
    Message.MinMaxInfo.ptMaxPosition.SetLocation(100,-8);
    Message.MinMaxInfo.ptMaxSize.SetLocation(200,200);
    Message.MinMaxInfo.ptMaxTrackSize := Message.MinMaxInfo.ptMaxSize;
    inherited;
  end;
  2, 3:
  begin
    Message.MinMaxInfo.ptMaxPosition.SetLocation(100,0);
    Message.MinMaxInfo.ptMaxSize.SetLocation(200,200);
    Message.MinMaxInfo.ptMaxTrackSize := Message.MinMaxInfo.ptMaxSize;
    inherited;
  end;
  4, 5:
  begin
    Message.MinMaxInfo.ptMaxPosition.SetLocation(100,100);
    Message.MinMaxInfo.ptMaxSize.SetLocation(200,200);
    Message.MinMaxInfo.ptMaxTrackSize := Message.MinMaxInfo.ptMaxSize;
    inherited;
  end;
end;

end;

end.

仅供参考:var Message: TWMGetMinMaxInfo似乎对表单生命周期持续存在。

在状态0,表单稍微移动到顶部,这告诉窗口管理器将此表单标题渲染得稍微小一点。这是最大化表单的默认行为,也是我搜索的光学结果

状态1将显示我遇到的问题,其他状态将显示可以在任何地方定位最大化的表单,并且标题栏在不切割屏幕边缘时将具有默认大小。

如果您想知道要为您的TForm选择什么偏移量,您可以使用AdjustWindowRectEx使用您选择的样式和主菜单信息来询问窗口。 (参见:VCL.Forms.pas,TCustomForm.GetClientRect实施)

答案 1 :(得分:1)

API窗口的标准标题是固定的,您无法改变其位置或大小。