Recent

Author Topic: What is the width and height of a form?  (Read 4016 times)

hakelm

  • Full Member
  • ***
  • Posts: 153
What is the width and height of a form?
« on: May 20, 2019, 01:44:02 pm »
I am trying to fill my screen with a number of forms but there must be some misunderstanding on my part.
When I execute the code below I get the forms, they fill the screen but they are overlapping.
What are the real top, left, width and height of a form?
H

Code: Pascal  [Select][+][-]
  1. unit testoverlappingformsform;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     procedure FormCreate(Sender: TObject);
  16.   private
  17.  
  18.   public
  19.  
  20.   end;
  21.  
  22. var
  23.   Form1: TForm1;
  24.  
  25. implementation
  26.  
  27. {$R *.lfm}
  28.  
  29. { TForm1 }
  30.  
  31. procedure TForm1.FormCreate(Sender: TObject);
  32. var n,t,l,w,h:integer; f:tform;
  33. begin
  34.   self.Visible:=false;
  35.   w:=screen.Width div 4;
  36.   h:=screen.Height div 4;
  37.   for n:=0 to 15 do begin
  38.     if n=0 then
  39.       f:=self
  40.     else
  41.       f:=tform.Create(self);
  42.     f.Left:=(n mod 4)*w;
  43.     f.top:=(n div 4)*h;
  44.     f.Width:=w;
  45.     f.Height:=h;
  46.     f.Visible:=true;
  47.     f.BringToFront;
  48.     f.Caption:=inttostr(n);
  49.   end;
  50. end;
  51.  
  52. end.
  53.  
« Last Edit: May 20, 2019, 01:45:35 pm by hakelm »

Josh

  • Hero Member
  • *****
  • Posts: 1271
Re: What is the width and height of a form?
« Reply #1 on: May 20, 2019, 02:05:05 pm »
Hi

Looks like your calculations are out by the width/height of the taskbar.

As a quick solution for a single monitor setup you could use
Screen.WorkAreaWidth   and Screen.WorkAreaHeight

If you wish to support Multiple Monitors then you will need to use some logic to handle the screen arrays.
screen.MonitorCount  holds how many monitors are connected.

then  screen[MonitorIndex].WorkAreaWidth holds Its width etc.

Hopefully you can get soemthing working from that.
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: What is the width and height of a form?
« Reply #2 on: May 20, 2019, 02:29:01 pm »
Looks like your calculations are out by the width/height of the taskbar.
No, they are not.
If that was the case, the second row would not be overlapped by the first.
Only the last row would pose a problem.

The problem here is that TForm.Height en TForm.Width is the same as TForm.ClientHeight and TForm.ClientWidth. There is no consideration for the titlebar and borders of the form. So each form will be higher than it should be (by the height of that titlebar). You need to set the TForm.Height - height of titlebar.

But "height of titlebar" is OS (and even theme) specific.

Imants

  • Full Member
  • ***
  • Posts: 196
Re: What is the width and height of a form?
« Reply #3 on: May 20, 2019, 03:46:41 pm »
Looks like your calculations are out by the width/height of the taskbar.
No, they are not.
If that was the case, the second row would not be overlapped by the first.
Only the last row would pose a problem.

The problem here is that TForm.Height en TForm.Width is the same as TForm.ClientHeight and TForm.ClientWidth. There is no consideration for the titlebar and borders of the form. So each form will be higher than it should be (by the height of that titlebar). You need to set the TForm.Height - height of titlebar.

But "height of titlebar" is OS (and even theme) specific.

Tried to use form ClientWidth and ClientHeight properties?

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: What is the width and height of a form?
« Reply #4 on: May 20, 2019, 03:51:57 pm »
Looks like your calculations are out by the width/height of the taskbar.
No, they are not.
If that was the case, the second row would not be overlapped by the first.
Only the last row would pose a problem.

The problem here is that TForm.Height en TForm.Width is the same as TForm.ClientHeight and TForm.ClientWidth. There is no consideration for the titlebar and borders of the form. So each form will be higher than it should be (by the height of that titlebar). You need to set the TForm.Height - height of titlebar.

But "height of titlebar" is OS (and even theme) specific.

Tried to use form ClientWidth and ClientHeight properties?
That doesn't work (like I already said).

For TForm the ClientHeight is the same as Height. You really need to calculate the outside form bounderies yourself (and substract these from the height).

And I'm not aware of any functions which are cross-platform to do so.

(See also from here forward: https://forum.lazarus.freepascal.org/index.php/topic,16166.msg87654.html#msg87654)

hakelm

  • Full Member
  • ***
  • Posts: 153
Re: What is the width and height of a form?
« Reply #5 on: May 20, 2019, 05:55:19 pm »
Thank you for your prompt help,
however, I am still confused but now on a higher level.
In order to explore the boundaries of a form I used the little attached program.
Main part of code below.

Typical results are:

startup
top 250 Left 471 Width 320 Height 240
wsMaximized
top 0 Left 0 Width 320 Height 240
ClientRect.Top 0 ClientRect.Left 0 ClientRect.Width 320 ClientHeight 240
wsfullscreen
top 0 Left 0 Width 320 Height 240
ClientRect.Top 0 ClientRect.Left 0 ClientRect.Width 320 ClientHeight 240
resised (with the form resised with th mouse to its maximum)
top 0 Left 0 Width 1870 Height 1028
ClientRect.Top 0 ClientRect.Left 0 ClientRect.Width 1870 ClientHeight 1028

The widgetsets all behaved differently with gtk (or was it qt?) making the least sense.

So I guess I will have to use experimentally established constants.
H

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   writeln('startup');
  4.   writeln('top ',top,' Left ',Left,' Width ',Width,' Height ', Height);
  5. end;
  6.  
  7. procedure TForm1.Button1Click(Sender: TObject);
  8. begin
  9.   self.WindowState:=wsMaximized;
  10.   application.ProcessMessages;  //just in case
  11.   writeln('wsMaximized');
  12.   writeln('top ',top,' Left ',Left,' Width ',Width,' Height ', Height);
  13.   writeln('ClientRect.Top ',self.ClientRect.Top,' ClientRect.Left ',ClientRect.Left,' ClientRect.Width ',self.ClientRect.Width,' ClientHeight ', self.ClientRect.Height);
  14. end;
  15.  
  16. procedure TForm1.Button2Click(Sender: TObject);
  17. begin
  18.   self.WindowState:=wsNormal;
  19.   application.ProcessMessages;
  20.   writeln('wsNormal');
  21.   writeln('top ',top,' Left ',Left,' Width ',Width,' Height ', Height);
  22.   writeln('ClientRect.Top ',self.ClientRect.Top,' ClientRect.Left ',ClientRect.Left,' ClientRect.Width ',self.ClientRect.Width,' ClientHeight ', self.ClientRect.Height);
  23. end;
  24.  
  25. procedure TForm1.Button3Click(Sender: TObject);
  26. begin
  27.   self.WindowState:=wsfullscreen;
  28.   application.ProcessMessages;
  29.   writeln('wsfullscreen');
  30.   writeln('top ',top,' Left ',Left,' Width ',Width,' Height ', Height);
  31.   writeln('ClientRect.Top ',self.ClientRect.Top,' ClientRect.Left ',ClientRect.Left,' ClientRect.Width ',self.ClientRect.Width,' ClientHeight ', self.ClientRect.Height);
  32. end;
  33.  
  34. procedure TForm1.Button4Click(Sender: TObject);
  35. begin
  36.   writeln('resised');
  37.   writeln('top ',top,' Left ',Left,' Width ',Width,' Height ', Height);
  38.   writeln('ClientRect.Top ',self.ClientRect.Top,' ClientRect.Left ',ClientRect.Left,' ClientRect.Width ',self.ClientRect.Width,' ClientHeight ', self.ClientRect.Height);
  39. end;      
« Last Edit: May 20, 2019, 06:43:45 pm by hakelm »

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: What is the width and height of a form?
« Reply #6 on: May 20, 2019, 09:22:44 pm »
Like I said. TForm.ClientHeight just doesn't work.
You could try to get the titlebar height with GetSystemMetrics() but I'm not sure how cross-platform that is.

You can come close to do a wsMaximized and get the height after that. But on Windows 10 that is still a bit off (I think because Windows 10 has a hidden border around the form without you seeing it).

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   n, t, l, w, h: integer;
  4.   f: TForm;
  5.   BorderHeight: Integer;
  6. begin
  7.   WindowState := wsMaximized;
  8.   BorderHeight := Screen.WorkAreaHeight - height;
  9.   // Showmessage(BorderHeight.ToString);
  10.  
  11.   self.Visible := False;
  12.   w := Screen.WorkAreaWidth div 4;
  13.   h := Screen.WorkAreaHeight div 4;
  14.   for n := 0 to 15 do
  15.   begin
  16.     if n = 0 then
  17.       f := self
  18.     else
  19.       f := TForm.Create(self);
  20.     f.Left := (n mod 4) * w;
  21.     f.top := (n div 4) * h;
  22.     f.Width := w;
  23.     f.Height := h - BorderHeight;
  24.     f.Visible := True;
  25.     f.BringToFront;
  26.     f.Caption := IntToStr(n);
  27.   end;
  28. end;

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: What is the width and height of a form?
« Reply #7 on: May 20, 2019, 10:01:47 pm »
That's a crazy kind of a design ...  :)

As rvk already said, you need to read out the theme settings...
A lot of people use a special border width and menu height and taskbar height and so on.
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

balazsszekely

  • Guest
Re: What is the width and height of a form?
« Reply #8 on: May 21, 2019, 12:17:57 pm »
This should work in every major widgetset:
Code: Pascal  [Select][+][-]
  1. var
  2.   FormCnt: Integer;
  3.   I, J: Integer;
  4.   W, H: Integer;
  5.   F: TForm;
  6. begin
  7.   FormCnt := 4;
  8.   W := Screen.WorkAreaWidth div FormCnt;
  9.   H := Screen.WorkAreaHeight div FormCnt;
  10.   for I := 0 to FormCnt - 1 do
  11.     for J := 0 to FormCnt - 1 do
  12.     begin
  13.       F := TForm.Create(Self);
  14.       F.Width := W - 2*(LCLIntf.GetSystemMetrics(SM_CYSIZEFRAME));
  15.       F.Height := H - (LCLIntf.GetSystemMetrics(SM_CYCAPTION) + 2*LCLIntf.GetSystemMetrics(SM_CYSIZEFRAME));
  16.       F.Left := Screen.WorkAreaLeft + W*J;
  17.       F.Top := Screen.WorkAreaTop + H*I;
  18.       F.Show;
  19.     end;
  20. end;

On windows 10 you have to get the extended information about the window, like this:
Code: Pascal  [Select][+][-]
  1. const
  2.   DWMWA_EXTENDED_FRAME_BOUNDS = 9;
  3.  
  4. function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall; external 'dwmapi.dll';
  5.  
  6. //...
  7.  
  8. var
  9.   Rect: TRect;
  10. begin
  11.   DwmGetWindowAttribute(Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @Rect, SizeOf(Rect));
  12. end;

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: What is the width and height of a form?
« Reply #9 on: May 21, 2019, 05:15:39 pm »
Is working here on W7 ...  :)
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

hakelm

  • Full Member
  • ***
  • Posts: 153
Re: What is the width and height of a form?
« Reply #10 on: May 26, 2019, 05:17:11 pm »
Thanks for all help especially for pointing me to GetSystemMetrics and Screen.
Enclosed is a project that fulfils my objectives.
The logic of the windows-logic sometimes eludes me and it was a bit of trial and error.
I had no use for SM_CYSIZEFRAME or SM_CXSIZEFRAME. Screen.Monitors[0].WorkareaRect.Left returns correct data only for the first monitor.
Another example is that you can easily move a window with the mouse so that it is partially outside the screen or straddles two monitors.
If you try to do that in code by setting for instance the height the window often refuses to accept the setting and even jumps back a number of pixels from the screen border or to another screen.
H

 

TinyPortal © 2005-2018