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

Delphi 如何删除wsNormal全屏表单标题栏内容偏移?,delphi,windows-10,vcl,titlebar,Delphi,Windows 10,Vcl,Titlebar,通过WindowsState:=wsMaximized最大化窗体时,标题栏如下所示: 将窗体设置为WindowsState:=wsNormal并手动将窗体大小设置为全屏状态时,框架的内容相同,但标题栏稍微移动 800*600屏幕上模拟wsMaxed表单的wsNormal表单为TRect(-8,-8808608)。 (见附件) 我的问题: 如何修复wsNormal窗口中移动的标题栏内容,使其看起来像下面的模型一样正确 带有一个按钮的简单示例表单,可复制两种表单状态 unit Unit1;

通过WindowsState:=wsMaximized最大化窗体时,标题栏如下所示:

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

800*600屏幕上模拟
wsMaxed
表单的
wsNormal
表单为TRect(-8,-8808608)。 (见附件)

我的问题: 如何修复wsNormal窗口中移动的标题栏内容,使其看起来像下面的模型一样正确

带有一个按钮的简单示例表单,可复制两种表单状态

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.
编辑1:

要澄清这可能有用的原因,请执行以下操作: 我们有一个具有相同分辨率屏幕的多显示器,希望在这个非常大的“虚拟屏幕”上跨越窗体。桌面无法通过AMDs虚拟Destkop设置统一到一个大屏幕

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


此外,还需要负位置和放大尺寸,实际的偏移/放大来自所选的边框样式。

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

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

通过发送
WM_GETMINMAXINFO
,表单将被询问在最大化情况下所需的位置和大小

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

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

告诉窗口管理器将边框样式隐藏在当前屏幕视图之外,也会导致。 现在,当WindowsState设置为
wsNormal
时,也会发生边缘溢出

偏移量还将告诉Windows窗口管理器,当它停靠到顶部时,要减小标题栏的大小,并正确呈现标题栏内容(,这是我们搜索的目标)

请参见以下示例:

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消息:TWMGetMinMaxInfo
似乎在表单生命周期内保持不变

在状态0时,表单稍微移到顶部,这会告诉窗口管理器将此表单标题稍微变小。这是最大化表单的默认行为和我搜索的光学结果

状态1将显示我遇到的问题,而其他状态将显示将最大化表单放置在任何位置都是可能的,并且当标题栏不切割屏幕边缘时,标题栏将具有默认大小


如果您想知道要为TForm选择什么偏移量,您可以通过使用所选样式和主菜单信息询问windows。(请参阅:VCL.Forms.pas,
TCustomForm.GetClientRect
implementation)

API窗口的标准标题是固定的,您不能做任何事情来改变其位置或大小。

您将表单定位在负偏移量处,并希望标题不会随之移动。我猜不出您希望使用哪种解决方案,但标题将始终固定在窗口上。我的解决方案是使用最大化的window而不是实体模型。如果您发现自己处于无法使用最大化窗口的情况下,您可能需要询问该问题。也许有一种方法可以指定标题rect,因此它将等于wsMaximized状态下的rect。不,标题将卡在现在的位置。也许您也希望模拟标题。这是没有意义。当你使用
wsMaximized
时,它可以正常工作,那么为什么你不直接使用
wsMaximized
?为什么你要使用
wsNormal
然后将表单过大以超过屏幕大小?如果你想要最大化窗口的行为,请最大化窗口,让操作系统完成它的工作。@Ken White,因为我们有一些lti监视器设置没有覆盖所有屏幕的虚拟桌面。使用wsMaximized可将窗体最大化为一个屏幕。使用wsNormal可覆盖所有屏幕。>“每个维度的值偏移量为8。“-这是不正确的。实际偏移量分别为水平和垂直方向的非客户指标
SM_CXFRAME
SM_CYFRAME
。您已经回答了应该问的问题。这个答案更适合“如何自定义窗口的最大化位置”之类的问题。它可能是重复的,但我不确定。偏移量取决于所选的边框样式。试试看。对于bsSingle,偏移量是3。是的,anwser是一个不同的问题。但我更愿意为这个问题找到一个解决方案,如果有的话。可能是通过Dsm建议的自定义样式。当然,您的帖子是关于带有大小边框的窗口,因此偏移量是SM|C[X|Y]YFRAME。单边框窗口的实际偏移量为SM|C[X | Y]FIXEDFRAME,而不是3。