Recent

Author Topic: Understanding Constraints  (Read 1418 times)

majolika

  • Jr. Member
  • **
  • Posts: 56
Understanding Constraints
« on: January 25, 2025, 04:23:39 pm »
Hello! First of all — a short introduction.
For self-education purposes, I am writing a small game: Mine Sweeper with RPG influence. Since I am completely unfamiliar with LCL, my development cycle looks like writing code → google → RTFM and repeat. But from time to time I really get stuck.

Now I am trying to figure out how Constraints work. I am using Lazarus 3.6 on Windows 10 if it matters.

As it is said in the documentation, Constraints have the highest priority above Aligning, Anchoring and so on, but maybe I understand something wrong. As I see, it works at design stage, but not at runtime.

Below is my test code.
Most of controls have MinHeight and/or MinWidth set.
When I set TForm1.AutoSize things go wrong. And when I resizing the main window manually things go even worse.
No doubt I'm missing something or misunderstand how Constraints work. But what?

In attach — published project,
screenshot 1 is what I expect (approximately),
screenshot 2 is what I get.

Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$R *.lfm}
  4.  
  5. procedure TForm1.Panel1Resize(Sender: TObject);
  6. begin
  7.   Label3.Top := ( Panel1.Height - (Label3.Height + Image2.Height) ) div 2;
  8. end;
  9.  
  10. procedure TForm1.FormCreate(Sender: TObject);
  11. begin
  12.   Self.AutoSize := True;
  13. end;
  14.  
  15. procedure TForm1.Button_FormHeight_minus_10Click(Sender: TObject);
  16. begin
  17.   self.Height := self.Height - 10;
  18. end;
  19.  
  20. procedure TForm1.Button_FormHeight_plus_10Click(Sender: TObject);
  21. begin
  22.     self.Height := self.Height + 10;
  23. end;
  24.  
  25. procedure TForm1.Button_FormWidth_minus_10Click(Sender: TObject);
  26. begin
  27.     self.Width := self.Width - 10;
  28. end;
  29.  
  30. procedure TForm1.Button_FormWidth_plus_10Click(Sender: TObject);
  31. begin
  32.   self.Width := self.Width + 10;
  33. end;
  34.  
  35. end.
  36.  
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #1 on: January 25, 2025, 04:52:34 pm »
// still not able to edit messages but anyway...

I'm planning that my main window will have top and bottom panels (anchored to the top and bottom of the main form) and the remaining client area will be taken by PaintBox. And when in the runtime I will be changing size of PaintBox the main window will change its size automatically. Of course, the main window should not be only autosized, but also change position. Perhaps it will be necessary to come up with a handler for TForm.OnResize, but I'll think about it a little later.
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

TRon

  • Hero Member
  • *****
  • Posts: 3978
Re: Understanding Constraints
« Reply #2 on: January 25, 2025, 08:55:17 pm »
start new (test) project
1. place first panel on form
2. set the align property of first panel to alTop
3. place second panel on form
4. set the align property of second panel to alBottom
5. place paintbox on form
6. set the align property of paintbox to alClient
7. Set constraints of paintbox to something desirable (you would have to change these at runtime according to your board size). for example I set them to 100 for both min and max in both directions
8. get back to the form properties, set autosize to true (might be you need to do that at runtime in order to avoid the crash you mentioned)
9. key change: set borderstyle to bsNone (*).

now try and run to see if that matches your criteria. The rest of the components placements and behaviour depends on these 3 components to be in place correctly.

(*) this can also be toolwindow in case you wish to have it look like a 'normal' window. The key point is to make the window non user resizeable.
« Last Edit: January 25, 2025, 09:02:44 pm by TRon »
I do not have to remember anything anymore thanks to total-recall.

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #3 on: January 25, 2025, 09:51:27 pm »
now try and run to see if that matches your criteria.
Thanks, TRon!! It works. Not quite what I expected, but... I'll think about it some more.
Anyway that's only a half of a battle. Now I need to understand why it works and why it works that way.
It seems to me that constraints work only with autosized controls (or more precisely — non user resizeable). But what's the logic?
I'm not a type of men who like ready-made solutions, I'm always try to understand the meaning of things, the logic of how things works.
Thanks again for your patience!
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

TRon

  • Hero Member
  • *****
  • Posts: 3978
Re: Understanding Constraints
« Reply #4 on: January 25, 2025, 10:03:51 pm »
The theory behind it is explained in the following wiki articles
- anchor sides
- anchors example
- autosize/layout

If you like reading as much as I am then you probably end up placing some components and fiddle with things to match the required behaviour  ;D

Note that even the order in which you place components could influence behaviour.

The anchoring and sizing design has gone through a major overhaul since their introduction to add more detailed control but it can work confusing.
I do not have to remember anything anymore thanks to total-recall.

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #5 on: January 25, 2025, 10:47:46 pm »
The theory behind it is explained in the following wiki articles
I've already read these articles. It gives me much more understanding about aligning and anchoring but there are too few about constraints.

If you like reading as much as I am then you probably end up placing some components and fiddle with things to match the required behaviour  ;D
That's exactly what I was doing today with my «test5» attached to the starting message of this topic. I was trying to make center panel looks "elastic" with labels and images proportionally adjusted on resizing.

Note that even the order in which you place components could influence behaviour.
That's the oddest part.

it can work confusing.
Oh yeah!
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

TRon

  • Hero Member
  • *****
  • Posts: 3978
Re: Understanding Constraints
« Reply #6 on: January 25, 2025, 11:03:53 pm »
There is indeed very little information to be found on the topic of constraints. But perhaps I am looking at the wrong place(s).
I do not have to remember anything anymore thanks to total-recall.

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #7 on: January 25, 2025, 11:09:56 pm »
Okay, I will learn through experience. :)
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

wp

  • Hero Member
  • *****
  • Posts: 12607
Re: Understanding Constraints
« Reply #8 on: January 26, 2025, 12:03:39 am »
In my opinion the main advantage of the Constraints is in cooperation with the AutoSize property.

Suppose there are two buttons on a form, one with caption 'OK', the other one with caption 'Cancel'. In order to make the layout independent of platform (often with different font size) or language (with longer/shorter caption texts), I'd set the AutoSize of the two buttons to true. But then the OK button is quite narrow compared to the Cancel button, and this looks odd. A possibility to fix this is to set the Constraints.MinWidth of both buttons to the same value - now both buttons will have the same width while still being able to adjust their height to the font size.

The question then is how to find the correct value for the Constraints.MinWidth? A clever way to do this is by code in an early event handler, such as the form's OnActivate, where the max button width (without Constraints) is determined and applied to the Constraints.MinWidth.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);
  2. var
  3.   w: Integer;
  4. begin
  5.   if FActivated then
  6.     exit;
  7.   w := OKButton.Width;
  8.   if CancelButton.Width > w then w := CancelButton.Width;
  9.   OKButton.Constraints.MinWidth := w;
  10.   CancelButton.Constraints.MinWidth := w;
  11.   FActivated := true;
  12. end;
The state variable FActivated here inhibits executing this code again and again if the form is activated several times.

I should also mention that automatic sizing of components must be accompanied by automatic placement. Because in case of fixed placement (dragging the components to their place with the mouse) neighbouring components will suddenly overlap in another language with longer caption texts! This is where the Anchor editor comes in. It allows to attach the left button ('OK') to the left side of its container and anchor the left side of the 'Cancel' button to the right side of the OK button, no matter how wide the OK button is. This way the Cancel button will be "pushed"/"dragged" by the OK button to its correct position. Or if you prefer the button to be on the right side, anchor the right side of the Cancel button to the right side of the container, and the right side of the OK button to the left side of the Cancel button.

The whole processing of working with the anchor editor is a bit complicated at first, and it may be scary because the controls no longer can be dragged by the mouse. But really it's worth the effort to learn it. Without anchoring the layout of a complex application like the Lazarus IDE would not work in so many operating systems and in so many languages. Just practice it with a simple layout.

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #9 on: January 26, 2025, 09:18:57 am »
Thanks for the good explanation!

In my opinion the main advantage of the Constraints is in cooperation with the AutoSize property.
I think it would have been more logical to use constraints to prevent control's overlapping or unwanted resizing during auto-aligning and auto-layouting but we have what we we have.
I believe it is done that way for a good reason. But the documentation lucks of information on how exactly constraints work and that leads me to a misunderstanding.
 
Quote
in order to make the layout independent of platform
Oh, that's another big topic I will study sometimes later...

Quote
Just practice it with a simple layout.
This is what my test5 project was about. :) It takes some time to read docs and google but finally I can make three groups of labels and images auto-layouted: they centered horizontally and vertically on the panel, and the spaces between is auto-sized that gives a taste of a flexible, elastic design. On the left of attached picture you can see an anchoring system I've made. But such design gives overlappings during manual resizing of the main window in the runtime (look on the right of attached picture). Misunderstanding of how the things work gives me an idea that I can prevent overlapping with constraints but no, I can't. Now I understand that constraints work with auto-sized controls and don't work with auto-aligned. I think it is possible to write my own OnResize handler to make constraints work in my way but the aligning/anchoring/layouting system is so complex that modifying it doesn't worth for a small project.
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #10 on: January 26, 2025, 10:07:11 am »
Oh, I know! I wish I could have in LCL a group of non-visual layouting controls that could be nested and can contains any other controls. Something like in Qt but incorporating all the LCL aligning, anchoring constrainting and z-positioning systems. Something like on a picture in first approximation.
Of course, there is TGroupBox but it's a visual control.
« Last Edit: January 26, 2025, 10:10:52 am by majolika »
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

wp

  • Hero Member
  • *****
  • Posts: 12607
Re: Understanding Constraints
« Reply #11 on: January 26, 2025, 12:00:39 pm »
Another option to align controls within a container is by using the ChildSizing property of the container. Suppose you want three groups of label and button aligned evenly so that all space of the container is filled.
  • Drop labels and buttons (in this order) onto a panel (or any other container (groupbox, tabsheet)
  • Open the ChildSizing subproperties of the panel in the object inspector.
  • Set ChildSizing.Layout to cclTopToBottomThenLeftToRight (to first fill the panel vertically by columns, and when the first column is full, proceed with the next column)
  • Set ControlsPerLine to 2 (note that since we are filling by columns this should be understood as "controls per column") - and now the labels and buttons are neatly aligned within the panel.
  • When you now set ChildSizing.EnlargeHorizontal to any other setting than crsAnchorAligning the controls are automatically expanded horizontally to fill the width of the panel. The individual options determine the algorithm how the available space is distributed amont the controls. For example, when you want the columns to have equal widths use crsSameSize. Or use crsScaleChilds to scale the controls proportional to their original width.
  • The same with ChildSizing.EnlargeVertical for the vertical direction, and with shrinking when the controls initially were too wide for the available space (ShrinkHorizontal and ShrinkVertical).
  • If you want additional space between the controls set the HorizontalSpacing (or VerticalSpacing for the vertical direction). And if you want additional space at the left/right side of the panel set LeftRightSpacing (or TopBottomSpacing).
  • If you want the change the position of individual controls within the panel you must use the Z-Order item in the context menu of the controls

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #12 on: January 26, 2025, 12:16:30 pm »
so that all space of the container is filled
And what if want labels and images have fixed sizes and act like one group during resizing theirs owner (for example. panel)?
I'm already done this but maybe not in a proper way.
« Last Edit: January 26, 2025, 12:24:29 pm by majolika »
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

wp

  • Hero Member
  • *****
  • Posts: 12607
Re: Understanding Constraints
« Reply #13 on: January 26, 2025, 12:36:52 pm »
I don't understand what this means exactly. Probably: use the crsHomogenousSpaceResize option in ChildSizing.EnlargeHorizontal/Vertical. This keeps the original size of the controls and adapts the spacing between the controls.

majolika

  • Jr. Member
  • **
  • Posts: 56
Re: Understanding Constraints
« Reply #14 on: January 26, 2025, 12:57:46 pm »
I don't understand what this means exactly.
Look at the attached picture.
Label1+Image+L1 forms one group, Label3+Image+L3 forms second group and Label5+Image+L5 — third group.
Red lines shows the anchors.
I want every group act like one control and be homogenously auto-positioned on the panel horizontally and vertically at the same time (for now it's only one visual row so vertically it's just centered).
As I use cclLeftToRightThenTopToBottom consraints do not work and groups overlapping on resizing. And I want to prevent overlapping.
I imagine it like every group to be stucked side by side when they reaches their minimal sizes and the whole window stops shrinking when it reaches a sum of minimal sizes of its components.
Think of it as an invisible grid which every cell can have their own aligning, anchoring, child-sizing and z-positioning rules. For now every group I made are the same but what if the groups will have different number of controls positioned (inside the group) differently?
« Last Edit: January 26, 2025, 01:30:00 pm by majolika »
Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64

 

TinyPortal © 2005-2018