3

When maximizing a Form via WindowState:=wsMaximized, the title bar looks like this:

Maximized form with a "normal" title bar

When setting the form to WindowState:=wsNormal and setting the form size manualy to a fullscreen state, the content of the frame is identical but the title bar is slightly moved.

enter image description here

The wsNormal form Rect on a 800*600 screen to simulate a wsMaxed form is TRect(-8,-8,808,608). (See this question why the difference of the size is necessary)

My Question: How can i fix the moved title bar content for the wsNormal window, so it would look correct like the following mock up?

enter image description here

Simple example form with one button, which reproduces both form states.

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:

To clarify why this might be usefull: We have a multi-monitor set up with identical resolution screens and want to span the form over this verly large "virtual screen. The desktop can not be unified to one large screen via e.g. AMDs Virtual Destkop settings.

The problem occurs because the title bar rect of a maximized Form has a slightly smaller height than a non-maximized form title bar.

Also, there is a need for the negative positions and enlarged size, caused by the (backwards compatible) way windows handles the border calculations and positioning. The actual offset/enlargement comes from the chosen borderstyle.

Community
  • 1
  • 1
Hugie
  • 455
  • 5
  • 17
  • 1
    You locate the form at a negative offset and want that the caption won't move with it. I can't guess what kind of solution do you hope for, but the caption will stick to the window at all times. My solution would be to use a maximized window instead of a mock up. If you found yourself in a situation that you can't use a maximized window, you may want to ask about that problem instead. – Sertac Akyuz Aug 10 '16 at 23:45
  • Maybe there is a way to specify the caption rect, so it would be equal to the rect in wsMaximized state. – Hugie Aug 10 '16 at 23:49
  • Nope, the caption will be stuck where it is now. Maybe you'd want to mock the caption too. – Sertac Akyuz Aug 10 '16 at 23:50
  • This makes no sense. It works right when you use `wsMaximized`, so why aren't you just using `wsMaximized`? Why are you using `wsNormal` and then oversizing the form to exceed the screen size? If you want the behavior of a maximized window, maximize the window and let the OS do its job. – Ken White Aug 11 '16 at 00:20
  • @Ken White Because we have some multi monitor setups without a virtual desktop covering all of them. Using wsMaximized will max the form to one screen. Using wsNormal allows to cover all screens. – Hugie Aug 11 '16 at 05:49
  • What about setting `Top` to -2 instead of -8? – Tom Brunberg Aug 11 '16 at 06:00
  • @Tom Brunberg Then the client area would also move by 6 pixel and would not be equal to the maxed forms area. – Hugie Aug 11 '16 at 06:33
  • Actually the content of the title bar is not necessarily the same for maximised and normal. Maybe it depends on the style, but certainly when I tried your example there is physically more white under the title text in normal mode than in maximised. – Dsm Aug 11 '16 at 08:28
  • @Dsm And that is exactly my problem. I would love to have a way to define the title bars rect, to force it to be drawn in a smaller region and to look similar. But i did not found anything, thats why i am searching for a solution here. – Hugie Aug 11 '16 at 09:05
  • I have also been looking and the answer may be styles. If you create your own style as a copy of the one you are using and switch to it when 'normalising', the bitmap style editor allows you to change Title Top, Title Bottom and caption left, which would seem to allow you to do what you want - although I haven't tried it yet. – Dsm Aug 11 '16 at 09:12

2 Answers2

2

After some research, i found a way to reach the Goal for the described Scenario with minimal effort. This does not answer the question itself, it will only reach the goal.

When a form is created and also when it is maximized (by either the user or setting the forms WindowState to wsMaximized), the window message WM_GETMINMAXINFO gets send.

With sending WM_GETMINMAXINFO, the Form will be asked about its desired position and size in a maximized situation.

Here, we can override windows default positioning and e.g. span a maximized view over multiple screens by setting the values accordingly.

When analyzing the default values sent via WM_GETMINMAXINFO message, the values will have an offset of 8 in each dimension.

The offset was necessary on older Windows OS to tell the window manager to hide the borderstyle outside of the current screens view, and would also result in edge bleeding on multi-monitor setup. The edge bleeding also occurs nowadays, when the WindowState is is set to wsNormal.

The Offset will also tell Windows Window Manager to reduce the title bars size when it is docked to the top AND to render the title bar content correctly (which is the goal we searched for).

See the following example:

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.

FYI: var Message: TWMGetMinMaxInfo seems to be persistent for the forms lifetime.

On state 0, the form is slightly moved into the top, which tells the window manager to render this forms title slightly smaller. This is the default behaviour for maximized forms and the optical result i searched for.

State 1 will show the problem i had, and the other states will show you that positioning a maximized form anywhere is possible AND that the title bar will have the default size when it is not cutting a screens edge.

If you want to know what offsets to pick for your TForm, you can ask windows by using AdjustWindowRectEx with your chosen styles and main menu informations. (See: VCL.Forms.pas, TCustomForm.GetClientRect implementation)

Community
  • 1
  • 1
Hugie
  • 455
  • 5
  • 17
  • > *" the values will have an offset of 8 in each dimension."* - This is incorrect. The actual offsets are the non client metrics `SM_CXFRAME` and `SM_CYFRAME`, horizontally and vertically respectively. – Sertac Akyuz Aug 11 '16 at 18:35
  • You have answered the question you should have ask. This answer would be better suited to a question "how can I customize my window's maximized position" or something like it. It would probably be a duplicate but I'm not sure of that. – Sertac Akyuz Aug 11 '16 at 18:38
  • The offset depends on the chosen borderstyle. Give it a try. For bsSingle, the offset will be 3. – Hugie Aug 11 '16 at 22:58
  • And yes, the anwser is kind of to a different question. But i would prefer to have a solution for the asked question, if there is one. Maybe it is via custom styles, as suggested by Dsm. – Hugie Aug 11 '16 at 23:03
  • Yes of course, your post is about a window with a sizing border, hence the offset is SM_C[X|Y]YFRAME. The actual offset for a single bordered window is SM_C[X|Y]FIXEDFRAME, rather than 3. – Sertac Akyuz Aug 11 '16 at 23:09
  • Custom styles is no different than mocking up a caption in any way you can imagine, you can draw anything you like. It wouldn't be an answer to have the actual caption at a different place than it is now. – Sertac Akyuz Aug 11 '16 at 23:11
  • Anyway, the value is an observation and is about having an offset. There may be more suitable ways to get the exact value for a arbitrary form and style. E.g. calling AdjustWindowRectEx with a zeroed rect will give you the correct x/y offset via right/bottom values. So you do not need to check the styles and pick the correct metric for it. – Hugie Aug 11 '16 at 23:21
1

The standard caption of an API window is fixed, you cannot do anything to alter its position or size.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169