Lazarus

Programming => General => Topic started by: hakelm on May 20, 2019, 01:44:02 pm

Title: What is the width and height of a form?
Post by: hakelm 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.  
Title: Re: What is the width and height of a form?
Post by: Josh 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.
Title: Re: What is the width and height of a form?
Post by: rvk 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.
Title: Re: What is the width and height of a form?
Post by: Imants 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?
Title: Re: What is the width and height of a form?
Post by: rvk 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)
Title: Re: What is the width and height of a form?
Post by: hakelm 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;      
Title: Re: What is the width and height of a form?
Post by: rvk 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;
Title: Re: What is the width and height of a form?
Post by: RAW 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.
Title: Re: What is the width and height of a form?
Post by: balazsszekely 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;
Title: Re: What is the width and height of a form?
Post by: RAW on May 21, 2019, 05:15:39 pm
Is working here on W7 ...  :)
Title: Re: What is the width and height of a form?
Post by: hakelm 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