Sign in Join
Wiki copytemporary

Autosize / Layout: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Overview
22
33The [[LCL]] can automatically alter a control's size and position so it adapts to changes in font, theme and text or other content. If you want to run your program on several platforms, or if your captions are available in several languages, your controls need to adapt correctly to their environment. The [[LCL]] allows you not only to make a quick first design (moving controls around on a form using the mouse) but also later to set several key properties which will make the controls automatically adapt subsequently to changed content etc.
44
55- Fixed design: this is the default when placing a control in the Designer. The control's position is fixed relative to its parent. The control's size and position (Left, Top) is fully adjustable by the programmer. You can move the control around with the mouse, and resize it freely.
66- Aligned: aligned controls fill up the remaining parental space at the top, bottom, left, or right, or fill the entire remaining space.
77- Anchored: you can anchor a control's sides (left, top, right, bottom) to its parent or to another control. Anchoring means: the [[LCL]] will try to maintain the same distance from the anchor point.
88- Layout: controls can be automatically aligned in rows and columns (e.g. TRadioGroup)
99- Custom via OnResize: you can align controls yourself in code using the OnResize and OnChangeBounds events.
1010- Custom controls: writing your own controls, you can override nearly every [[LCL]] behaviour you want.
1111
1212### Precedence rules
1313
14141. Constraints
15152. Align
16163. Anchors
17174. ChildSizing.Layout
18185. AutoSize
19196. OnResize, OnChangeBounds - however, if you set bounds that conflict with the rules above you will create an endless loop
2020
2121### Common Properties
2222
2323Several important properties can be changed to configure autosizing:
2424
2525- Left, Top, Width, Height
2626- AutoSize: autosize instructs the [[LCL]] to automatically resize the Width and Height of a control
2727- Anchors: lets you create dependencies, for example to anchor a ComboBox to the right side of a Label.
2828- Align
2929- Constraints: lets you set a minimum and maximum for the Width and Height
3030- BorderSpacing: lets you set the spacing between anchored controls
3131- ChildSizing: lets you set the layout and spacing of child controls
3232
3333The internals of the algorithms are explained here: [[LCL AutoSizing]].
3434
3535## Fixed design
3636
3737Fixed design is the default. The Anchor's property is set to \[akLeft,akTop\], which means the values of Left and Top are not changed by the [[LCL]]. If AutoSize is false, the [[LCL]] does not alter Width or Height. If AutoSize is true, the Width and Height are changed to fit the content. For example, TLabel.AutoSize defaults to true and thus changing its Caption will resize the label to accommodate the changed wording. TButton.AutoSize defaults to false, so changing a button's Caption does not resize the button. When you set Button.AutoSize to true the Button will shrink or enlarge every time the button's Caption or its font (or theme) changes. Note, this change does not always happen immediately. For example during FormCreate all autosizing is suspended. At any time you can change the "Left", "Top", "Width", or the "Height" property.
3838
3939## AutoSize
4040
4141`AutoSize` is a boolean property found in many classes; it permits the size of a control to be adjusted automatically to accommodate differences in the text or graphic contained therein, and allows most efficient use of available space. This is a crucial mechanism to create cross platform forms.
4242
4343Normally AutoSize=true does two things for a visible control:
4444
4545- If possible it resizes the control to the preferred size. For example a TButton's Width and Height is resized to fit the caption, while a TEdit is only resized in Height. A TEdit's Width is not autosized. You can change the Width of a TEdit. (see GetPreferredSize).
4646- It moves all fixed positioned child controls by the same amount, so that the leftmost child control is moved to Left=0 (depends on BorderSpacing) and the topmost child control is moved to Top=0.
4747
4848### Lazarus vs Delphi
4949
5050- Delphi's AutoSize happens only when certain properties change, for example when the Font of a TLabel is changed. The [[LCL]] AutoSize is always active. Delphi allows one to change the size of a Label which has AutoSize=true, the Lazarus control does not.
5151- Delphi's hidden controls are not autosized.
5252- With Delphi, changing the size of a control does not resize/move anchored child controls during loading, but a constructor is normally used to make the desired effect. When using akRight,akBottom anchors, set AnchorSides and BorderSpacing to keep the distance correct.
5353
5454### AutoSize and resizing the control
5555
5656With AutoSize=false buttons are given a default fixed size.
5757
58-<figure>
59-<img src="Autosize1.png" title="Autosize1.png" />
60-<figcaption>Autosize1.png</figcaption>
61-</figure>
58+![](/wiki-images/1/1f/Autosize1.png)
6259
6360When setting AutoSize=true for each button, the buttons are enlarged (or shrunk) to fit the text and theme frame.
6461
65-<figure>
66-<img src="Autosize_on.png" title="Autosize_on.png" />
67-<figcaption>Autosize_on.png</figcaption>
68-</figure>
62+![](/wiki-images/7/75/Autosize_on.png)
6963
7064AutoSize does not shrink to the smallest possible size as you can see in the OK Button. It uses the GetPreferredSize method of the control, which calls the CalculatePreferredSize method. The default TWinControl implementation queries the widget set, which might have a preferred width or height. Each control can override the CalculatePreferredSize method. For example TImage overrides it and returns the size of the Picture. If no preferred width (height) is available the returned value is 0 and the [[LCL]] will keep the Width (Height) (unless the ControlStyle flag csAutoSize0x0 is set, which is currently only used by TPanel).
7165
7266A TWinControl computes the size of all its child controls and uses that to compute its preferred size.
7367
7468When a control is anchored to both left and right its *width is fixed*. For example with *Align=alTop* the control is anchored to left and right and follows the width of the Parent. If *Parent.AutoSize* is true, then the *Parent* will use the preferred width of the control to compute its own preferred width, and thus the control will be resized to its preferred width. See [[Autosize / Layout|Align and AutoSize]]. If no preferred width is available, then the last set bounds are used (**BaseBounds** or **ReadBounds**). If no bounds were set, the **GetControlClassDefaultSize** method is used. Same for **Height** and anchoring to top and bottom.
7569
7670Constraints are always applied and have precedence.
7771
7872### AutoSize and moving child controls
7973
8074When AutoSize=false you can place and move controls freely:
8175
82-<figure>
83-<img src="Autosize_on.png" title="Autosize_on.png" />
84-<figcaption>Autosize_on.png</figcaption>
85-</figure>
76+![](/wiki-images/7/75/Autosize_on.png)
8677
8778When AutoSize=true child controls with fixed positions are moved to fit.
8879
89-<figure>
90-<img src="Autosize_panel_on.png" title="Autosize_panel_on.png" />
91-<figcaption>Autosize_panel_on.png</figcaption>
92-</figure>
80+![](/wiki-images/d/d9/Autosize_panel_on.png)
9381
9482Both buttons on the panel were moved by the same amount to top and left, so that there is no space left to the left and top. If the buttons would have BorderSpacing\>0 or the Panel.ChildSizing.LeftRightSpacing\>0 the buttons would be moved so that the defined space is used.
9583
9684Only child controls with the following values are moved:
9785
9886- Anchors=\[akLeft,akRight\]
9987- AnchorSide\[akLeft\].Control=nil
10088- AnchorSide\[akTop\].Control=nil
10189- Align=alNone
10290
10391The moving of the child controls depend on the propert [[Autosize / Layout|ChildSizing.Layout]]. The layout is applied in the method TWinControl.AlignControls which can be overridden completely or in parts. For example TToolBar overrides ControlsAligned to position all controls with Align=alCustom and defines a flow layout where controls that do not fit are put into subsequent lines.
10492
10593Controls can disable the moving of child controls by setting the ControlStyle flag csAutoSizeKeepChildLeft and csAutoSizeKeepChildTop (since 0.9.29).
10694
10795### AutoSize and Forms
10896
10997Forms without Parent are controlled by the window manager and can therefore not be placed or resized freely. Setting the size is only a recommendation and might be ignored by the window manager. For example you might set the Width of a Form to 1000 and the widget set might answer with a resize to 800. If you set the Width in OnResize you might create an endless loop. That's why the [[LCL]] TForm disables AutoSize when the widget set resizes the form.
11098
11199That means AutoSize for forms stops when the user resizes the form or if the window manager does not like the bounds. For example some Linux window managers have features like magnetic sides which resizes windows in relationship to other windows.
112100
113101#### Force the auto sizing of a form
114102
115103You can start/execute a new AutoSize by doing:
116104
117105``` pascal
118106Form1.AutoSize := False;
119107Form1.AutoSize := True;
120108```
121109
122110#### Compute the size of an autosized form in advance
123111
124112When placing an autosized form you might need the size of the form before showing it. Autosizing requires the handle. You can compute the size of a form before showing it with:
125113
126114``` pascal
127115Form1.HandleNeeded;
128116Form1.GetPreferredSize(PreferredWidth,PreferredHeight);
129117```
130118
131119**Note**: The window manager and form events might change the size. The preferred size does not include the form's window borders. This is a planned feature.
132120
133121## Anchor Sides
134122
135123Controls have four sides: akLeft, akTop, akRight and akBottom. Each side can be anchored to the parent or the side of another sibling (a control with the same parent). Anchoring means **keeping the distance**. The default is Anchors=\[akLeft,akTop\]. Vertical anchors are independent of horizontal anchors. Some properties like Align and Parent.AutoSize have higher precedence and can change the behaviour.
136124
137125### Anchored to Parent or Nil
138126
139127Anchoring to Nil (the default) has almost the same effect as anchoring to the Parent. Both try to keep the distance to a side of the Parent's client area. Anchoring to Nil uses the distance of the last SetBounds call, while Anchoring to Parent uses the BorderSpacing value.
140128
141129There are four combinations of akLeft,akRight (akTop,akBottom):
142130
143131- **akLeft, no akRight**: the control's **Left** is fixed and not changed by the [[LCL]]. The right side is not anchored, so it follows the left side. That means the **Width** is kept too.
144132- **akLeft and akRight**: the control's **Left** is fixed and not changed by the [[LCL]]. The right side is anchored to the Parent's right side. That means if the Parent is enlarged by 100pixel then the control's **Width** is enlarged by 100pixel too.
145133- **akRight, no akLeft**: the control's left side is not anchored, so it will follow its right side. The right side is anchored. That means if the parent is enlarged by 100pixel then the control is moved to the right by 100pixel.
146134- **no akLeft and no akRight**: neither sides are anchored. The position of the center of the control scales with the parent. For example if the control is in the middle of the parent and the parent is enlarged by 100 pixel, then the control is moved 50pixel to the right.
147135
148136#### Changing the size of the parent of an anchored control
149137
150138When changing the size of a parent all anchored child controls are moved and/or resized immediately unless AutoSizing is disabled. For example AutoSizing is disabled during loading of a form and during creation of a form.
151139
152140A GroupBox with a Button: ![](/wiki-images/6/60/Anchors1.png)
153141
154142When the GroupBox is enlarged the distance of the anchored side is kept:
155143
156144With akLeft, no akRight: ![](/wiki-images/0/05/Anchors_akLeft.png)
157145
158146With akLeft and akRight: ![](/wiki-images/6/66/Anchors_akLeft_akRight.png)
159147
160148With akRight, no akLeft: ![](/wiki-images/d/d3/Anchors_akRight_no_akLeft.png)
161149
162150Three buttons in a groupbox: ![](/wiki-images/4/48/Anchors_no_akLeft_no_akRight_small.png)
163151
164152With no akLeft and no akRight their centers are scaled: ![](/wiki-images/7/7b/Anchors_no_akLeft_no_akRight_big.png)
165153
166154**Notes:**
167155
168156- Loading a form is like one big SetBounds. During loading properties are set using the values of the lfm. Keep in mind that there can be multiple lfm files because of ancestors and frames. After loading the [[LCL]] enables autosizing. Anchored controls use the bounds at the end of loading. Any step in between is ignored.
169157- For custom controls it is often better to set AnchorSides instead of only Anchors.
170158
171159#### Changing the size of an anchored control
172160
173161When changing the Width of an anchored control, for example via the Object Inspector or via code *Button1.Width:=3*, you can see the difference between anchoring to *Parent* and anchoring to *Nil*. Anchoring to Parent will resize and move the Button1, while anchoring to Nil will only resize. For example:
174162
175163##### Anchored to nil
176164
177165![](/wiki-images/b/bd/Anchored_right_nil_resize1.png) A Button1 anchored \[akTop,akRight\], AnchorSide\[akRight\].Control=nil
178166
179167![](/wiki-images/a/a0/Anchored_right_nil_resize2.png) Setting the Width to a smaller value will shrink the button, keeping the button's *Left*, increasing the distance of the right side.
180168
181169![](/wiki-images/1/16/Anchored_right_nil_resize3.png) When the Groupbox is resized the button will keep the new distance.
182170
183171**Explanation:** setting the **Width** is equivalent to calling SetBounds(**Left**,Top,**NewWidth**,Height). That's why the *Left* is kept. This is Delphi compatible.
184172
185173##### Anchored to Parent
186174
187175![](/wiki-images/4/45/Anchored_right_parent_resize1.png) A Button1 anchored \[akTop,akRight\], AnchorSide\[akRight\].Control=Button1.Parent
188176
189177![](/wiki-images/0/04/Anchored_right_parent_resize2.png) Setting the Width to a smaller value will shrink the button, keeping the right distance, changing the button's *Left*.
190178
191179#### Anchored to sibling
192180
193181You can anchor to neighbor controls. The following example shows:
194182
195183- you can anchor a label's left to the left of a button
196184- anchor a label's top to the bottom of a button
197185- anchor the center of a label to the center of a button
198186
199-<figure>
200-<img src="Anchorsides_example1.png" title="Anchorsides_example1.png" />
201-<figcaption>Anchorsides_example1.png</figcaption>
202-</figure>
187+![](/wiki-images/e/ee/Anchorsides_example1.png)
203188
204-<figure>
205-<img src="Anchorside_example2.png" title="Anchorside_example2.png" />
206-<figcaption>Anchorside_example2.png</figcaption>
207-</figure>
189+![](/wiki-images/b/ba/Anchorside_example2.png)
208190
209191For more details and how to setup anchors see: [[Anchor Sides]].
210192
211-<figure>
212-<img src="Anchoreditor.png" title="Anchoreditor.png" />
213-<figcaption>Anchoreditor.png</figcaption>
214-</figure>
193+![](/wiki-images/6/6d/Anchoreditor.png)
215194
216195### BorderSpacing
217196
218197The BorderSpacing properties controls the minimum amount of space around a control. The properties are:
219198
220199- **Around**: this amount in pixel is added to Left, Top, Right, Bottom.
221200- **Left**: space in pixel on the left side of the control
222201- **Top**: space in pixel above the control
223202- **Right**: space in pixel on the right side of the control
224203- **Bottom**: space in pixel below the control
225204- **InnerBorder**: this amount in pixel is added twice to the preferred width and height. Some controls override the calculation and ignore this property. An example where it works is TButton. With InnerBorder you can make a button bigger than needed.
226205- **CellAlignHorizontal**: This is used in table layouts like ChildSizing.Layout=cclLeftToRightThenTopToBottom. If the control is smaller than the table cell, this property defines where to align the control: to the left ccaLeftTop, to the right ccaRightBottom or in the middle ccaCenter.
227206- **CellAlignVertical**: same as CellAlignHorizontal but for vertical alignment.
228207
229208#### BorderSpacing rules
230209
231210- Around is added to Left,Top,Right,Bottom borderspacing
232211- The space can be even bigger, if the controls have constraints that don't allow to expand.
233212
234213##### Anchoring to the opposite side
235214
236215For example right side of A to left side of B.
237216
238217Both borderspacings of A and B are used.
239218
240219- The horizontal space between two controls (LeftControl, RightControl on Parent) is the maximum of
241220 - LeftControl.BorderSpacing.Right + LeftControl.BorderSpacing.Around
242221 - RightControl.BorderSpacing.Left + RightControl.BorderSpacing.Around
243222 - Parent.ChildSizing.HorizontalSpacing
244223- The vertical space works analog: between two controls (TopControl, BottomControl on Parent) is the maximum of
245224 - TopControl.BorderSpacing.Bottom + TopControl.BorderSpacing.Around
246225 - BottomControl.BorderSpacing.Top + BottomControl.BorderSpacing.Around
247226 - Parent.ChildSizing.VerticalSpacing
248227
249228For instance if LeftControl.BorderSpacing.Right = 3 and LeftControl.BorderSpacing.Around = 4, then there is at least 7 pixel space between the two controls. If RightControl.BorderSpacing.Left = 4 and RightControl.BorderSpacing.Around = 4 then the space will be at least 8. If Parent.ChildSizing.HorizontalSpacing = 10 then the space will be at least 10.
250229
251230##### Anchoring to the same side
252231
253232For example right side of A to right side of B.
254233
255234- Only borderspacings of A is used.
256235- Parent.ChildSizing.Horizontal/VerticalSpacing are not used.
257236
258237##### Anchoring to center
259238
260239For example center of A to center of B.
261240
262241No borderspacing is used and no Parent.ChildSizing.Horizontal/VerticalSpacing is used.
263242
264243##### Example
265244
266245A common example is anchoring a Label to an Edit.
267246
268-<figure>
269-<img src="BorderSpacing_Anchors.png" title="BorderSpacing_Anchors.png" />
270-<figcaption>BorderSpacing_Anchors.png</figcaption>
271-</figure>
247+![](/wiki-images/1/1e/BorderSpacing_Anchors.png)
272248
273249The Label center is vertically anchored to the Edit. The Edit's left side is anchored to the right side of the Label. Both have BorderSpacing.Around=6. This results in 6 pixel space between the Label and the Edit and 6 pixel space left of the Label and 6 pixel space right of the Edit. There is 6 pixel space above and below the Edit as well.
274250
275251- The left space between a control and its parent (Label1 on GroupBox1) is the maximum of
276252 - Label1.BorderSpacing.Left + Label1.BorderSpacing.Around
277253 - GroupBox1.ChildSizing.LeftTopSpacing
278254
279255- The right space between a control and its parent (Edit1 on GroupBox1) is the maximum of
280256 - Edit1.BorderSpacing.Right + Edit1.BorderSpacing.Around
281257 - GroupBox1.ChildSizing.RightBottomSpacing
282258
283259- When a control's center is anchored to another control, for example the above Label is centered vertically to the Edit1, then all spacings are ignored.
284260
285261- When a control's left side is anchored to the left side of another control (i.e. they are aligned with the left side), then the distance between both left's side is the
286262 - Control1.BorderSpacing.Left + Control1.BorderSpacing.Around
287263
288264Here is a more complex example:
289265
290-<figure>
291-<img src="Borderspacing_anchors2.png" title="Borderspacing_anchors2.png" />
292-<figcaption>Borderspacing_anchors2.png</figcaption>
293-</figure>
266+![](/wiki-images/9/9c/Borderspacing_anchors2.png)
294267
295268The important parts of the lfm code:
296269
297270``` pascal
298271 object GroupBox1: TGroupBox
299272 AutoSize = True
300273 Caption = 'GroupBox1'
301274 TabOrder = 0
302275 object Label1: TLabel
303276 AnchorSideLeft.Control = GroupBox1
304277 AnchorSideTop.Control = Edit1
305278 AnchorSideTop.Side = asrCenter
306279 BorderSpacing.Around = 6
307280 Caption = 'Label1'
308281 end
309282 object Edit1: TEdit
310283 AnchorSideLeft.Control = Label1
311284 AnchorSideLeft.Side = asrBottom
312285 AnchorSideTop.Control = GroupBox1
313286 AnchorSideRight.Control = GroupBox1
314287 AnchorSideRight.Side = asrBottom
315288 Anchors = [akTop, akLeft, akRight]
316289 BorderSpacing.Around = 6
317290 TabOrder = 0
318291 Text = 'Edit1'
319292 end
320293 object Label2: TLabel
321294 AnchorSideLeft.Control = GroupBox1
322295 AnchorSideTop.Control = Edit1
323296 AnchorSideTop.Side = asrBottom
324297 BorderSpacing.Around = 6
325298 Caption = 'Label2'
326299 end
327300 object ComboBox1: TComboBox
328301 AnchorSideLeft.Control = Label2
329302 AnchorSideTop.Control = Label2
330303 AnchorSideTop.Side = asrBottom
331304 AnchorSideRight.Control = GroupBox1
332305 AnchorSideRight.Side = asrBottom
333306 Anchors = [akTop, akLeft, akRight]
334307 BorderSpacing.Right = 6
335308 TabOrder = 1
336309 Text = 'ComboBox1'
337310 end
338311 object CheckBox1: TCheckBox
339312 AnchorSideLeft.Control = GroupBox1
340313 AnchorSideTop.Control = ComboBox1
341314 AnchorSideTop.Side = asrBottom
342315 BorderSpacing.Around = 6
343316 Caption = 'CheckBox1'
344317 TabOrder = 2
345318 end
346319 object Label3: TLabel
347320 AnchorSideLeft.Control = GroupBox1
348321 AnchorSideTop.Control = Edit2
349322 AnchorSideTop.Side = asrCenter
350323 BorderSpacing.Around = 6
351324 Caption = 'Label3'
352325 end
353326 object Edit2: TEdit
354327 AnchorSideLeft.Control = Label3
355328 AnchorSideLeft.Side = asrBottom
356329 AnchorSideTop.Control = CheckBox1
357330 AnchorSideTop.Side = asrBottom
358331 BorderSpacing.Around = 6
359332 TabOrder = 3
360333 Text = 'Edit2'
361334 end
362335 end
363336```
364337
365338#### BorderSpacing and Align
366339
367340BorderSpacing works with Align. In the example below there is a Memo1 with Align=alTop and a Memo2 with Align=alCLient.
368341
369342- Normally the two Memos would fill the whole GroupBox.
370343- But the Memo1 has BorderSpacing.Around=10, so there 10 pixel space around Memo1.
371344- The Memo2 has BorderSpacing.Top=20. The space between Memo1 and Memo2 is the maximum, which is the 20 from Memo2.
372345- Memo2 has also BorderSpacing.Right=50 so there is 50 Pixel space right of Memo2.
373346- The GroupBox can define default space for all its child controls via ChildSizing.LeftRightSpacing/VerticalSpacing/HorizontalSpacing. In this example it does not (all 0).
374347
375-<figure>
376-<img src="Borderspacing_align1.png" title="Borderspacing_align1.png" />
377-<figcaption>Borderspacing_align1.png</figcaption>
378-</figure>
348+![](/wiki-images/1/13/Borderspacing_align1.png)
379349
380350## Align
381351
382352The Align property works pretty much like in Delphi and can be used to quickly fill an area. For example to let a TListBox fill the entire area of its Parent, set ListBox1.Align=alClient. The align values alTop, alBottom, alLeft and alRight will place controls without overlapping if possible. That means all controls with Align in alLeft,alTop,alBottom,alRight will not overlap if there is enough space.
383353
384354The algorithm works as follows:
385355
386356- First all controls with alTop are put to the top of the client area. If there are several controls with alTop the last added/moved will be put topmost. The algorithm will try to avoid overlapping and keep the height of the control, while expanding the width to maximum. AnchorSides of the left, top and right sides are ignored. The bottom AnchorSide works normal. Borderspacing and Parent.ChildSizing spaces are considered, so you can define space around each aligned control.
387357- Then all controls with alBottom are put to the bottom of the client area. Otherwise it works analog to alTop.
388358- Then all controls with alLeft are put to the left of the client area between the alTop and alBottom controls. Otherwise it works analog to alTop.
389359- Then all controls with alRight are put to the right of the client area between the alTop and alBottom controls. Otherwise it works analog to alTop.
390360- If there is a control with alClient it will fill the remaining client.
391361- If there is more than one control with alClient they will be placed at the same position, overlapping each other. Use the Visibility property to define which one is shown.
392362
393-<figure>
394-<img src="Autosize_align.png" title="Autosize_align.png" />
395-<figcaption>Autosize_align.png</figcaption>
396-</figure>
363+![](/wiki-images/e/e6/Autosize_align.png)
397364
398365### Align and BorderSpacing
399366
400367The space of BorderSpacing and of the parent's ChildSizing is applied to aligned controls. The memo below has Align=alClient.
401368
402-<figure>
403-<img src="Autosize_align_borderspacing.png" title="Autosize_align_borderspacing.png" />
404-<figcaption>Autosize_align_borderspacing.png</figcaption>
405-</figure>
369+![](/wiki-images/b/b4/Autosize_align_borderspacing.png)
406370
407371### Align and Anchoring
408372
409373The free side of an aligned control (e.g. the right side of a **Align=alLeft**) follows the anchoring rules. If the anchor is not set, then the control will keep its **Width**. If the anchor is set, then the **Width** will change.
410374
411375### Align and AutoSize
412376
413377A control aligned with alLeft or alRight expands vertically, and will use its designed width. If *AutoSize* is set to *true*, then the *Width* will be the preferred width. The button below has *Align=alRight* and *AutoSize=true*.
414378
415-<figure>
416-<img src="Autosize_align_autosize.png" title="Autosize_align_autosize.png" />
417-<figcaption>Autosize_align_autosize.png</figcaption>
418-</figure>
379+![](/wiki-images/3/35/Autosize_align_autosize.png)
419380
420381### Align and parent AutoSize
421382
422383A control aligned with alClient fills the remaining space. A parent control with *AutoSize=true* will expand or shrink to enclose its children exactly. What happens if you combine these two properties? Say you put a button with Align=alClient into a groupbox with AutoSize=true?
423384
424-<figure>
425-<img src="Autosize_nested1.png" title="Autosize_nested1.png" />
426-<figcaption>Autosize_nested1.png</figcaption>
427-</figure>
385+![](/wiki-images/b/b1/Autosize_nested1.png)
428386
429387The [[LCL]] uses the *preferred size* of the buttons and expands or shrinks the groupbox accordingly:
430388
431-<figure>
432-<img src="Autosize_nested2.png" title="Autosize_nested2.png" />
433-<figcaption>Autosize_nested2.png</figcaption>
434-</figure>
389+![](/wiki-images/2/28/Autosize_nested2.png)
435390
436391### alCustom
437392
438393This Align value exists for custom AutoSize algorithms and is treated by the [[LCL]] almost like alNone. Controls with alCustom are not moved by the [[LCL]] but by your custom control. You have to override CalculatePreferredSize and DoAutoSize.
439394
440395### Order of controls with same Align
441396
442397Controls with same Align are positioned in the following order. On alLeft the control with the lowest Left wins, for alTop the lowest Top, for alRight the biggest Left+Width, for alBottom the biggest Top+Height. If two controls have the same coordinate the one last moved (calls to SetBounds or SetParent) wins. Controls can override CreateControlAlignList to change the order or override DoAlignChildControls to handle the whole Align.
443398
444399Note: Before 0.9.29 controls at the same coordinate were put in Z order. This resulted in reordering in some cases and had to be fixed. There is one incompatibility: If you added several controls with alTop or alLeft without specifying bounds the controls are put at 0,0 and therefore the last added wins, where formerly the first won.
445400
446401Note for Delphians: Contrary to the VCL the LCL can and often does delay recomputing the layout. Delphi does the layout after every property change. Setting Align=alTop calls in the VCL a special AlignControls, where the current control has a special meaning. That's why in the VCL the order of setting properties is important. The LCL layout algorithm is independent of the chronological order of setting the properties.
447402
448403For example all changes in FormCreate are delayed and the layout is computed from the final property values. On the other hand ButtonClick has no delay (aka you have to add the Disable/EnableAutoSize yourself), so inserting alTop controls may have different results.
449404
450405If you want a specific order, use Disable/EnableAutoSize and set the "Top" properties. For example TForm.OnCreate is called with AutoSize disabled, so you can use:
451406
452407``` pascal
453408procedure TForm1.FormCreate(Sender: TObject);
454409begin
455410 // making sure Panel2 is above Panel1, even though Panel1 is set first:
456411 Panel1.Align:=alTop;
457412 Panel1.Top:=1;
458413 Panel2.Align:=alTop;
459414 Panel2.Top:=0;
460415end;
461416```
462417
463418## Layout
464419
465420### Rows, columns and lines
466421
467422You can align child controls in rows and columns using the ChildSizing properties. For example:
468423
469424- ChildSizing.Layout=cclLeftToRightThenTopToBottom
470425- ChildSizing.ControlsPerLine=3
471426- AutoSize=false (the groupbox does not resize to fit the child controls)
472427
473-<figure>
474-<img src="Autosize_layout_lefttoright.png" title="Autosize_layout_lefttoright.png" />
475-<figcaption>Autosize_layout_lefttoright.png</figcaption>
476-</figure>
428+![](/wiki-images/1/10/Autosize_layout_lefttoright.png)
477429
478430The **Layout** property defaults to cclNone. If you set **Layout** to another value, every child, that has *normal* anchors, will be aligned. *Normal* anchors means:
479431
480432- Anchors=\[akLeft,akTop\]
481433- AnchorSide\[akLeft\].Control=nil
482434- AnchorSide\[akTop\].Control=nil
483435- Align=alNone
484436
485437The value **cclLeftToRightThenTopToBottom** will put the first child at top, left, the second to the right, and so forth. This is a **line**. The property **ControlsPerLine** defines when a new line is started. In the above example each line (row) has 3 controls. There are 12 controls, so there are 4 lines (rows) each with 3 controls (columns). If *ControlsPerLine* is 0 it means unlimited controls per line - there would be only one row with all childs.
486438
487439You can see that the rows have different sizes, each row has the size of the biggest control and that the controls are resized to column width. There is no space between the rows. The space in the image comes from the used theme, not from the [[LCL]].
488440
489441### Fixed space between rows and columns
490442
491443You can add space between with these properties:
492444
493445- ChildSizing.VerticalSpacing - Space between rows
494446- ChildSizing.HorizontalSpacing - Space between columns
495447- ChildSizing.LeftRightSpacing - Space on the left and right of *all* columns
496448- ChildSizing.TopBottomSpacing - Space above and below of *all* columns
497449
498450The above example with ChildSizing.VerticalSpacing=6, ChildSizing.HorizontalSpacing=15, ChildSizing.LeftRightSpacing=30, ChildSizing.TopBottomSpacing=10, AutoSize=true
499451
500-<figure>
501-<img src="Autosize_layout_parentspacing.png" title="Autosize_layout_parentspacing.png" />
502-<figcaption>Autosize_layout_parentspacing.png</figcaption>
503-</figure>
452+![](/wiki-images/a/a9/Autosize_layout_parentspacing.png)
504453
505454Additionally you can add individual space for each control with its BorderSpacing properties.
506455
507456### Enlarge
508457
509458The above example resized the GroupBox to the needed space. If your GroupBox has a fixed size or if it is not freely resizable, for instance if the GroupBox should fill the whole width of the form, then the childs should enlarge. There are several modes. The default mode *ChildSizing.EnlargeHorizontal=crsAnchorAligning* is to not enlarge anything. The space on the right side will be unused.
510459
511460- crsAnchorAligning - do not use the extra space
512461- crsScaleChilds - multiply the width/height with the same factor
513462- crsHomogeneousChildResize - add to each width/height the same amount
514463- crsHomogeneousSpaceResize - add to each space between the childs the same amount
515464
516465#### crsScaleChilds
517466
518467ChildSizing.EnlargeHorizontal=crsScaleChilds, ChildSizing.EnlargeVertical=crsScaleChilds, AutoSize=false
519468
520-<figure>
521-<img src="Autosize_layout_scalechilds.png" title="Autosize_layout_scalechilds.png" />
522-<figcaption>Autosize_layout_scalechilds.png</figcaption>
523-</figure>
469+![](/wiki-images/b/b0/Autosize_layout_scalechilds.png)
524470
525471For example if the ClientWidth is twice as big as needed, then every child will be twice as big.
526472
527473#### crsHomogeneousChildResize
528474
529475ChildSizing.EnlargeHorizontal=crsHomogeneousChildResize, ChildSizing.EnlargeVertical=crsHomogeneousChildResize, AutoSize=false
530476
531-<figure>
532-<img src="Autosize_layout_homogeneouschildresize.png" title="Autosize_layout_homogeneouschildresize.png" />
533-<figcaption>Autosize_layout_homogeneouschildresize.png</figcaption>
534-</figure>
477+![](/wiki-images/3/39/Autosize_layout_homogeneouschildresize.png)
535478
536479For example if the ClientWidth is 30 pixel bigger than needed, then every child will be 10 pixel broader.
537480
538481#### crsHomogeneousSpaceResize
539482
540483ChildSizing.EnlargeHorizontal=crsHomogeneousSpaceResize, ChildSizing.EnlargeVertical=crsHomogeneousSpaceResize, AutoSize=false
541484
542-<figure>
543-<img src="Autosize_layout_homogeneousspaceresize.png" title="Autosize_layout_homogeneousspaceresize.png" />
544-<figcaption>Autosize_layout_homogeneousspaceresize.png</figcaption>
545-</figure>
485+![](/wiki-images/9/96/Autosize_layout_homogeneousspaceresize.png)
546486
547487For example if the ClientWidth is 40 pixel bigger than needed, there will be 10 pixel space on the left, right and between each child.
548488
549489### Shrink
550490
551491Shrinking works similarly to enlarging. You can set different modes if there is not enough space for controls. **ShrinkHorizontal**, **ShrinkVertical**.
552492
553493### Individual cells
554494
555495In the above examples all controls were resized the same, each filled the whole *cell*. A *cell* is the space in a specific row and column. Normally a control fills the whole cell space. This can be changed with the properties **BorderSpacing.CellAlignHorizontal** and **BorderSpacing.CellAlignVertical**.
556496
557497For example set the *BorderSpacing.CellAlignHorizontal* of the fifth button to **caCenter** you will get this:
558498
559-<figure>
560-<img src="Autosize_layout_cellhorizontal_cacenter.png" title="Autosize_layout_cellhorizontal_cacenter.png" />
561-<figcaption>Autosize_layout_cellhorizontal_cacenter.png</figcaption>
562-</figure>
499+![](/wiki-images/d/d3/Autosize_layout_cellhorizontal_cacenter.png)
563500
564501There are four possible values for CellAlignHorizontal/CellAlignVertical:
565502
566503- caFill: the child control fills the whole width (height) of the cell
567504- caCenter: the child control uses its preferred width (height) and will be centered in the cell
568505- caLeftTop: the child control uses its preferred width (height) and will be leftaligned in the cell
569506- caRightBottom: the child control uses its preferred width (height) and will be rightaligned in the cell
570507
571-<figure>
572-<img src="Autosize_layout_cellalign.png" title="Autosize_layout_cellalign.png" />
573-<figcaption>Autosize_layout_cellalign.png</figcaption>
574-</figure>
508+![](/wiki-images/c/c0/Autosize_layout_cellalign.png)
575509
576510## Custom layout with OnResize / OnChangeBounds
577511
578512Sometimes the [[LCL]] layout is not sufficient. The below example shows a GroupBox1 with a ListBox1 and a Memo1. The ListBox1 should fill one third of the space, the Memo1 takes the rest.
579513
580-<figure>
581-<img src="Autosize_onresize.png" title="Autosize_onresize.png" />
582-<figcaption>Autosize_onresize.png</figcaption>
583-</figure>
514+![](/wiki-images/4/4b/Autosize_onresize.png)
584515
585516Whenever the GroupBox is resized the ListBox1.Width should be one third. To achieve this set the OnResize event of the GroupBox1 to:
586517
587518``` pascal
588519procedure TForm1.GroupBox1Resize(Sender: TObject);
589520begin
590521 ListBox1.Width := GroupBox1.ClientWidth div 3;
591522end;
592523```
593524
594525### Common mistake: Wrong OnResize event
595526
596527Do not put *all* your resizing code into the Form OnResize event. The Form OnResize event is only called when the Form was resized. The child controls (e.g. a GroupBox1) is resized later, so the GroupBox1.ClientWidth has still the old value during the FormResize event. You must use the GroupBox1.OnResize event to react to changes of GroupBox1.ClientWidth.
597528
598529### Common mistake: Width instead of ClientWidth, AdjustClientRect
599530
600531The Width is the size including the frame. The ClientWidth is the inner Width without the frame. Some controls like the TPanel paints a further frame. Then you have to use AdjustClientRect. The same example, but instead of a GroupBox1 the ListBox1 is in a Panel1:
601532
602533``` pascal
603534procedure TForm1.Panel1Resize(Sender: TObject);
604535var
605536 r: TRect;
606537begin
607538 r := Panel1.ClientRect;
608539 Panel1.AdjustClientRect(r);
609540 ListBox1.Width := (r.Right - r.Left) div 3;
610541end;
611542```
612543
613544## Custom Controls
614545
615546When you write your own control, you can override and fine tune many parts of the [[LCL]] autosizing.
616547
617548### SetBounds, ChangeBounds, DoSetBounds
618549
619550**SetBounds** is called when the properties Left, Top, Width, Height, BoundsRect is set or the user calls it directly. SetBounds updates the BaseBounds and BaseParentClientSize, which are used by anchoring to keep the distance. For example loading a Form with TMemo and the lfm contains TMemo's Left and Width, then SetBounds is called two times for the memo. When the user maximizes a window, SetBounds is called for the form, but not for the Memo, keeping the BaseBounds of the Memo. If the Memo is anchored to the right, the Width of the Memo is changed based on the BaseBounds and BaseParentClientSize. Keep in mind that the given aLeft, aTop, aWidth, aHeight might not be valid and will be changed by the [[LCL]] before applied. Delphi calls SetBounds more often. SetBounds calls ChangeBounds with KeepBase=false.
620551
621552**ChangeBounds** is called whenever the position or size of the control is set, either via the properties or by the layouter of the [[LCL]]. SetBounds calls internally ChangeBounds with KeepBase=false, while the [[LCL]] layouter calls it with KeepBase=true. Override this for code that might change the preferred size or resizes other controls. Keep in mind that the given aLeft, aTop, aWidth, aHeight might not be valid and will be changed by the [[LCL]] before applied. You can call this function.
622553
623554**DoSetBounds** is a low level function to set the private variables FLeft, FTop, FWidth, FHeight. Do not call this function, only the [[LCL]] calls it. It also updates FClientWidth and FClientHeight accordingly. Override this to update the content layout of the control, for example scroll bars. As always: do not paint here, but call Invalidate and paint in OnPaint or override Paint.
624555
625556**DoAdjustClientRectChange** is called by the [[LCL]] and the [[LCL]] interface, when the ClientRect has changed and the Width and Height were kept.
626557
627558**WMSize** exists for Delphi/VCL compatibility. It is called by the [[LCL]] interface and on every change of bounds.
628559
629560### AdjustClientRect
630561
631562The method AdjustClientRect can be overriden by your custom controls and affects Align, ChildSizing.Layout and AnchorSides. It does not affect the meaning of Left, Top and does not affect normal anchoring (for example setting).
632563
633564When you want to draw your own frame, then the child controls should be aligned within these frames. For example TPanel draws a frame and reduces the client area by overriding the method **AdjustClientRect**:
634565
635566``` pascal
636567 TCustomPanel = class(TCustomControl)
637568 ...
638569 protected
639570 ...
640571 procedure AdjustClientRect(var aRect: TRect); override;
641572 ...
642573
643574procedure TCustomPanel.AdjustClientRect(var aRect: TRect);
644575var
645576 BevelSize: Integer;
646577begin
647578 inherited AdjustClientRect(aRect);
648579
649580 BevelSize := BorderWidth;
650581 if (BevelOuter <> bvNone) then
651582 inc(BevelSize, BevelWidth);
652583 if (BevelInner <> bvNone) then
653584 inc(BevelSize, BevelWidth);
654585
655586 InflateRect(aRect, -BevelSize, -BevelSize);
656587end;
657588```
658589
659590#### AdjustClientRect and Align
660591
661592AdjustClientRect can be used to reduce the client area used by all autosize operations. For example TPanel uses AdjustClientRect to reduce the client area by the borderwidth:
662593
663-<figure>
664-<img src="Adjustclientrect_align.png" title="Adjustclientrect_align.png" />
665-<figcaption>Adjustclientrect_align.png</figcaption>
666-</figure>
594+![](/wiki-images/c/ca/Adjustclientrect_align.png)
667595
668596The Button1 in the screenshot was created with Align=alClient. ChildSizing.Layout is affected too.
669597
670598When anchoring to a parent via AnchorSides the AdjustClientRect is used too:
671599
672600``` pascal
673601 Button1.AnchorParallel(akTop,0,Button1.Parent);
674602```
675603
676604The Button1's top side is anchored to the top side of the parent's client area. If the AdjustClientRect adds 3 to the Top the Button1.Top will be 3 (3 plus 0).
677605
678606### Own AutoSize
679607
680608When *AutoSize* is set to true the control should be resized to the preferred size if possible.
681609
682610#### Preferred Size
683611
684612The new size is fetched by the [[LCL]] via **GetPreferredSize** which calls **CalculatePreferredSize**, which can be overridden. For example let's write a **TQuadrat**, which is a TShape, but its height should equal its width:
685613
686614``` pascal
687615 TQuadrat = class(TShape)
688616 protected
689617 procedure CalculatePreferredSize(var PreferredWidth,
690618 PreferredHeight: integer; WithThemeSpace: Boolean); override;
691619 end;
692620...
693621procedure TQuadrat.CalculatePreferredSize(var PreferredWidth,
694622 PreferredHeight: integer; WithThemeSpace: Boolean);
695623begin
696624 PreferredHeight:=Width;
697625end;
698626```
699627
700628The method CalculatePreferredSize gets two var parameters: *PreferredWidth* and *PreferredHeight*. They default to 0 which means: there is no preferred size, so the [[LCL]] will not change the size. The above function sets *PreferredHeight* to the current *Width*. The boolean parameter *WithThemeSpace* is deprecated and always false.
701629
702630**Important**: CalculatePreferredSize must not change the bounds or any other value of the control that can trigger an autosize. Doing so will create a loop.
703631
704632Computing the *PreferredWidth/Height* can be expensive. Therefore the [[LCL]] caches the result until *InvalidatePreferredSize* is called for the control. In our example the *PreferredHeight* depends on the *Width*, so we must invalidate when the *Width* changes:
705633
706634``` pascal
707635 TQuadrat = class(TShape)
708636 protected
709637 ...
710638 procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
711639 end;
712640...
713641procedure TQuadrat.DoSetBounds(ALeft, ATop, AWidth, AHeight: integer);
714642begin
715643 inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
716644 InvalidatePreferredSize;
717645 // Note: The AdjustSize can be omitted here, because the [[LCL]] does that after calling DoSetBounds.
718646end;
719647```
720648
721649The [[LCL]] will automatically trigger the autosizing when the bounds have changed, so the example is complete.
722650
723651The default TWinControl implementation of CalculatePreferredSize queries the widget set, which might return a preferred width and/or height. Each control can override the CalculatePreferredSize method. For example TImage overrides it and returns the size of the Picture. If no preferred width (height) is available the returned value is 0 and the [[LCL]] will keep the current Width (Height). If 0 is a valid size for your control, you must set the ControlStyle flag csAutoSize0x0 (ControlStyle:=ControlStyle+\[csAutoSize0x0\];). An example is the [[LCL]] control TPanel.
724652
725653#### AdjustSize
726654
727655When the preferred size depends on a new property, then every time the property changes the auto sizing must be triggered. For example:
728656
729657``` pascal
730658procedure TQuadrat.SetSubTitle(const AValue: string);
731659begin
732660 if FSubTitle = AValue then exit;
733661 FSubTitle := AValue;
734662 InvalidatePreferredSize;
735663 AdjustSize;
736664end;
737665```
738666
739667## Reduce overhead with DisableAutoSizing, EnableAutoSizing
740668
741669Since Lazarus 0.9.29 there is a new autosizing algorithm, that reduces the overhead and allows deep nested dependencies. Up to 0.9.28 DisableAlign/EnableAlign and Disable/EnableAutoSizing worked only for one control and its direct child controls.
742670
743671Each time you change a property the [[LCL]] triggers a recomputation of the layout:
744672
745673``` pascal
746674Label1.Caption := 'A'; // first recompute
747675Label2.Caption := 'B'; // second recompute
748676```
749677
750678The recomputations will trigger events and send messages. To reduce the overhead you can suspend the autosizing:
751679
752680``` pascal
753681DisableAutoSizing;
754682try
755683 Label1.Caption := 'A'; // no recompute
756684 Label2.Caption := 'B'; // no recompute
757685finally
758686 EnableAutoSizing; // one recompute
759687end;
760688```
761689
762690You must balance calls to Disable/EnableAutoSizing. Autosizing starts only when EnableAutoSizing is called after a corresponding (earlier) DisableAutoSizing.
763691
764692Since 0.9.29 the Disable/EnableAutoSizing works for the entire form. This means every call to DisableAutoSizing suspends autosizing for **all** controls on that form. If you write your own control you can now use the following:
765693
766694``` pascal
767695procedure TMyRadioGroup.DoSomething;
768696begin
769697 DisableAutoSizing; // disables not only TMyRadioGroup, but the whole form's autosizing
770698 try
771699 // delete items ...
772700 // add, reorder items ...
773701 // change item captions ...
774702 finally
775703 EnableAutoSizing; // recompute
776704 end;
777705end;
778706```
779707
780708Which basically means: you do not have to care. Just call Disable/EnableAutoSizing.
781709
782710Note: this is wrong:
783711
784712``` pascal
785713Button1.DisableAutoSizing;
786714Label1.EnableAutoSizing; // wrong: every control has its own autosizing reference counter
787715```
788716
789717### DisableAutoSizing and Form bounds
790718
791719DisableAutoSizing has another useful effect under asynchronous Window Managers such as you find in Linux systems. Each time a form is resized or moved the bounds are sent to the widget set (DoSendBoundsToInterface). Even if the form is not shown the Handle is resized. The window manager often treats these bounds only as a proposal. The window manager has its own logic and often only the first bounds sent are used. The second, third or further moves may be ignored. With DisableAutoSizing you can make sure that only the final bounds are sent to the widget set making the form bounds more reliable.
792720
793721## Example: a button panel
794722
795723This example combines several of the [[LCL]] layout mechanisms to create a panel with three buttons: a *Help* button to the left and *Ok* and *Cancel* buttons to the right. We want the panel to be at the bottom of the form filling the entire width. The buttons and the panel are autosized to fit all fonts and themes.
796724
797725Step 1: Create the panel and set its Align property to alBottom. Add three TBitBtns.
798726
799-<figure>
800-<img src="Autosize_example_buttonpanel1.png" title="Autosize_example_buttonpanel1.png" />
801-<figcaption>Autosize_example_buttonpanel1.png</figcaption>
802-</figure>
727+![](/wiki-images/7/7e/Autosize_example_buttonpanel1.png)
803728
804729Set the *Kind* properties of the BitBtns to show the glyphs. You might need to set GlyphShowMode to gsmAlways to see them on your platform. Set the BitBtn's *AutoSize* property to *True*, which will shrink/enlarge the buttons to fit perfectly around the glyphs and text. Depending on your theme and platform you might notice that the buttons have different heights.
805730
806-<figure>
807-<img src="Autosize_example_buttonpanel2.png" title="Autosize_example_buttonpanel2.png" />
808-<figcaption>Autosize_example_buttonpanel2.png</figcaption>
809-</figure>
731+![](/wiki-images/4/49/Autosize_example_buttonpanel2.png)
810732
811733Set the *Align* property of the help button to *alLeft* and set the other two buttons' *Align* property to *alRight*. This will enlarge the buttons vertically and move them to the far left/right. alLeft/alRight has no effect on the width, so the buttons use their preferred width.
812734
813-<figure>
814-<img src="Autosize_example_buttonpanel3.png" title="Autosize_example_buttonpanel3.png" />
815-<figcaption>Autosize_example_buttonpanel3.png</figcaption>
816-</figure>
735+![](/wiki-images/b/b6/Autosize_example_buttonpanel3.png)
817736
818737The Panel height is still fixed. Now set the panel *AutoSize* property to *True*. The panel now shrinks vertically to fit the tallest button.
819738
820-<figure>
821-<img src="Autosize_example_buttonpanel4.png" title="Autosize_example_buttonpanel4.png" />
822-<figcaption>Autosize_example_buttonpanel4.png</figcaption>
823-</figure>
739+![](/wiki-images/3/36/Autosize_example_buttonpanel4.png)
824740
825741The *Ok* button has a short caption, so the button is very small. Set the button's *Constraints.MinWidth* to *75*. The button will now enlarge somewhat.
826742
827-<figure>
828-<img src="Autosize_example_buttonpanel5.png" title="Autosize_example_buttonpanel5.png" />
829-<figcaption>Autosize_example_buttonpanel5.png</figcaption>
830-</figure>
743+![](/wiki-images/3/32/Autosize_example_buttonpanel5.png)
831744
832745Now add some space around the buttons. Set the panel's *ChildSizing.LeftTopSpacing/RightBottomSpacing/HorizontalSpacing* to *6*.
833746
834-<figure>
835-<img src="Autosize_example_buttonpanel6.png" title="Autosize_example_buttonpanel6.png" />
836-<figcaption>Autosize_example_buttonpanel6.png</figcaption>
837-</figure>
747+![](/wiki-images/4/46/Autosize_example_buttonpanel6.png)
838748
839749Finally clear the *Caption* of the panel and set its *BevelOuter* to *bvNone*.
840750
841-<figure>
842-<img src="Autosize_example_buttonpanel7.png" title="Autosize_example_buttonpanel7.png" />
843-<figcaption>Autosize_example_buttonpanel7.png</figcaption>
844-</figure>
751+![](/wiki-images/4/4e/Autosize_example_buttonpanel7.png)
845752
846753## Scrolling
847754
848755Some [[LCL]] controls like *TScrollBox*, *TForm*, and *TFrame* show scrollbars if the child controls are too big to fit the scrollbox, form or frame. They inherit this behaviour from their ancestor **TScrollingWinControl**.
849756
850757A scrolling control's **logical client area** can be bigger than the **visible client area**. The *visible client area* is **ClientRect**. It always starts at 0,0 and its width and height is the inner area. For example in a TGroupBox it is the size of the area inside the frame. So the following is always true:
851758
852759``` pascal
853760ClientWidth <= Width
854761ClientHeight <= Height
855762```
856763
857764The **logical client area** is defined by the method **GetLogicalClientRect**. By default it is the same as *ClientRect*. When a child control is anchored to the right side, it uses the *logical client area*. *TScrollingWinControl* overrides this method and returns the *Range* of the scrollbars if they are bigger than the *ClientRect*. The **Range** can be set manually or automatically with *AutoScroll=true*. An example for *AutoScroll=true*:
858765
859-<figure>
860-<img src="Autoscroll_all_fit1.png" title="Autoscroll_all_fit1.png" />
861-<figcaption>Autoscroll_all_fit1.png</figcaption>
862-</figure>
766+![](/wiki-images/d/db/Autoscroll_all_fit1.png)
863767
864768The upper button has a fixed Width of 200. The lower button is anchored to the right side of the panel. Therefore the child controls have a preferred width of 200. Because the panel is bigger than 200 the logical client area is bigger too and the lower button expands.
865769
866770Now the panel is shrunk, so that the ClientWidth becomes lower than 200:
867771
868-<figure>
869-<img src="Autoscroll_not_fit1.png" title="Autoscroll_not_fit1.png" />
870-<figcaption>Autoscroll_not_fit1.png</figcaption>
871-</figure>
772+![](/wiki-images/2/27/Autoscroll_not_fit1.png)
872773
873774The preferred width is still 200, so the logical client area is now 200 and bigger than the visible client area. The lower button has now a Width of 200 and the panel shows a horizontal scrollbar.
874775
875776### Scroll Position
876777
877778Changing the Position of a scrollbar does not change the Left or Top of any child control, nor does it change the logical client area, nor does it affect autosizing. The child controls are only virtually moved.
878779
879780### Scrolling and AutoSize
880781
881782When AutoSize=true the [[LCL]] will expand the control to accommodate all its child controls, and no scrollbars are needed. If the control cannot be expanded, then (only) is the secondary action of AutoSize executed: moving the child controls.
882783
883784## Docking
884785
885786Docking uses the described methods and properties of this page, see [[Docking]].
886787
887788## Splitter
888789
889790See [[TSplitter]].
890791
891792## TLabel.WordWrap
892793
893794**TLabel.WordWrap** changes the behavior of the preferred size of the label. **WordWrap=true** requires that the Width of the label is fixed, for example by anchoring the left and right size of the label. The preferred height of the label is then computed by breaking the Caption into multiple lines.
894795
895796## DPI auto-adjustment and absolute layout auto-adjustment
896797
897798Historically the [[LCL]] has been utilized mostly to design absolute layouts, despite the huge amount of options which Lazarus offers for flexible layouts, like Align, Anchors, etc, as described on the rest of this article. On top of that, it has also historically ignored the DPI of the target and instead utilized values in pixels to measure the left, top, width and height properties of controls. For desktop platforms and Windows CE this has worked reasonably well, but with the advent of [[LCL]] support for Android this could no longer be ignored. Starting in Lazarus 0.9.31 the [[LCL]] can reinterprete the [[LCL]] absolute layout in pixels as a flexible grid. There are multiple modes to choose from and they will allow to reinterprete the pixel values as either really absolute, or as in being adjusted for the DPI or as in being considered simply a fraction of the form size.
898799
899800It is important to note that these new rules affect only controls which are positioned without Align and with the most standard Anchors only.
900801
901802In the case where the values will be adjusted for DPI, there is a new property: TCustomForm.DesignTimeDPI which should store the DPI value of the system where the form was designed. The positioning values will be expanded when the target DPI is larger than the design time DPI or reduced otherwise. The common value for desktop DPIs is 96 and is the default value given.
902803
903804property DesignTimeDPI: Integer read FDesignTimeDPI write FDesignTimeDPI;
904805
905806The way in which the layout is adjusted can be controlled with the property TApplication.LayoutAdjustmentPolicy
906807
907808``` pascal
908809 TLayoutAdjustmentPolicy = (
909810 lapDefault, // widget set dependent
910811 lapFixedLayout, // A fixed absolute layout in all platforms
911812 lapAutoAdjustWithoutHorizontalScrolling, // Smartphone platforms use this one,
912813 // the x axis is stretched to fill the screen and
913814 // the y is scaled to fit the DPI
914815 lapAutoAdjustForDPI // For desktops using High DPI, scale x and y to fit the DPI
915816 );
916817```
917818
918819And the following new methods in TControl allow to force a layout-autoadjustment in a particular control and all its children or to control how particular descendants of TControl react to this:
919820
920821``` pascal
921822TControl = class
922823public
923824...
924825 procedure AutoAdjustLayout(AMode: TLayoutAdjustmentPolicy;
925826 const AFromDPI, AToDPI, AOldFormWidth, ANewFormWidth: Integer); virtual;
926827 function ShouldAutoAdjustLeftAndTop: Boolean; virtual;
927828 function ShouldAutoAdjustWidthAndHeight: Boolean; virtual;
928829```
929830
930831LCL-CustomDrawn-Android will call AutoAdjustLayout when the screen rotates, for example.
931832
932833## More details
933834
934835Many controls override *TControl.DoAutoSize* to perform the actual auto-sizing.
935836
936837IMPORTANT: Many Delphi controls override this method and many call this method directly after setting some properties.
937838
938839During handle creation not all interfaces can create complete Device Contexts which are needed to calculate things like text size.
939840
940841That's why you should always call *AdjustSize* instead of `DoAutoSize`.
941842
942843`TControl.AdjustSize` calls `DoAutoSize` in a smart fashion.
943844
944845During loading and handle creation the calls are delayed.
945846
946847This method initially does the same as *TWinControl.DoAutoSize*. But since `DoAutoSize` is commonly overriden by descendant components, it is not useful to perform all tests, which can result in too much overhead. To reduce this the [[LCL]] calls `AdjustSize` instead.
947848
948849When setting AutoSize = true the [[LCL]] autosizes the control in width and height. This is one of the most complex parts of the [[LCL]], because the result depends on nearly a hundred properties. Let's start simple:
949850
950851The [[LCL]] will only autosize the *Width* (Height) if it is free to resize. In other words - the width is not autosized if:
951852
952853- the left and right side is anchored. You can anchor the sides with the **Anchors** property or by setting the *Align* property to alTop, alBottom or alClient.
953854- the *Width* is bound by the *Constraints* properties. The Contraints can also be overriden by the widget set. For example the winapi does not allow resizing the height of a combobox. And the gtk widget set does not allow resizing the width of a vertical scrollbar.
954855
955856Same for *Height*.
956857
957858The new size is calculated by the protected method **TControl.CalculatePreferredSize**. This method asks the widget set for an appropriate Width and Height. For example a TButton has preferred Width and Height. A TComboBox has only a preferred Height. The preferred Width is returned as 0 and so the [[LCL]] does not autosize the Width - it keeps the width unaltered. Finally a TMemo has no preferred Width or Height. Therefore AutoSize has no effect on a TMemo.
958859
959860Some controls override this method. For example the TGraphicControl descendants like TLabel have no window handle and so cannot query the widget set. They must calculate their preferred Width and Height themselves.
960861
961862The widget sets must override the GetPreferredSize method for each widget class that has a preferred size (Width or Height or both).
962863
963864### Parent.AutoSize
964865
965866The above described the simple explanation. The real algorithm provides far more possibilities and is therefore far more complex.
966867
967868### Properties / Methods
968869
969870- Left
970871- Top
971872
972873If Parent\<\>nil then Left, Top are the pixel distance to the top, left pixel of the parent's client area (not scrolled). Remember the client area is always *without* the frame and scrollbars of the parent. For Delphi users: Some VCL controls like TGroupbox define the client area as the whole control including the frame and some not - the [[LCL]] is more consistent, and therefore Delphi incompatible. Left and Top can be negative or bigger than the client area. Some widget sets define a minimum/maximum somewhere around 10.000 or more.
973874
974875When the client area is scrolled the Left and Top are kept unchanged.
975876
976877During resizing/moving Left and Top are not always in sync with the coordinates of the Handle object.
977878
978879If Parent=nil then Left, Top depend on the widget set and the window manager. Till Lazarus 0.9.25 this is typically the screen coordinate of the left,top of the client area of the form. This is Delphi incompatible. It is planned to change this to the Left, Top of the window.
979880
980881Hint: Each time you change Left and Top the [[LCL]] moves instantly and recomputes the whole layout. If you want to change Left *and* Top use instead:
981882
982883``` pascal
983884with Button1 do
984885 SetBounds(NewLeft, NewTop, Width, Height);
985886```
986887
987888- Width
988889- Height
989890
990891The Size in pixels must not be negative, and most widget sets do not allow Width=0 and/or Height=0. Some controls on some platforms define a bigger minimum constraint in Constraints.MinInterfaceWidth/Height. Instead of sizing a control to Width=0 and/or Height=0, set Visible=false or Parent=nil. During resizing/moving Width and Height are not always in sync with the size of the Handle object.
991892
992893- BoundsRect
993894
994895Same as Bounds(Left, Top, Width, Height).
995896
996897Common newbie mistake:
997898
998899``` pascal
999900BoundsRect.Left := 3; // WRONG: common newbie mistake
1000901```
1001902
1002903This has no effect, because reading BoundsRect is a function. It creates a temporary TRect on the stack. The above is the same as
1003904
1004905``` pascal
1005906var
1006907 r: TRect;
1007908begin
1008909 r := BoundsRect; // fetch the bounds
1009910 r.Left := 3; // change a value on the stack
1010911end; // no change
1011912```
1012913
1013914- ClientRect
1014915
1015916Left and Top are always 0,0. Width and Height are the visible size in pixels of the client area. Remember the client area is without the frame and without scrollbars. In a scrollable client area the logical client area can be bigger than the visible.
1016917
1017918- ClientOrigin
1018919
1019920Returns the screen coordinate of the topleft coordinate 0,0 of the client area. Note that this value is the position as stored in the interface and is not always in sync with the [[LCL]]. When a control is moved, the [[LCL]] sets the bounds to the desired position and sends a move message to the interface. It is up to the interface to handle moves instantly or queued.
1020921
1021922- LCLIntf.GetClientBounds
1022923
1023924Returns the client bounds of a control. Like ClientRect, but Left and Top are the pixel distances to the control's left, top. For example on a TGroupBox the Left, Top are the width and height of the left and top frame border. Scrolling has no effect on GetClientBounds.
1024925
1025926- LCLIntf.GetWindowRect
1026927
1027928After the call, ARect will be the control area in screen coordinates. That means, Left and Top will be the screen coordinate of the TopLeft pixel of the Handle object and Right and Bottom will be the screen coordinate of the BottomRight pixel.
1028929
1029930- FBaseBoundsLock: integer
1030931
1031932Increased/Decreased by LockBaseBounds/UnlockBaseBounds. Used to keep FBaseBounds during SetBounds calls.
1032933
1033934- FBaseParentClientSize: TPoint
1034935
1035936The Parent.ClientRect size valid for the FBaseBounds. FBaseBounds and FBaseParentClientSize are used to calculate the distance for akRight (akBottom). When the parent is resized, the [[LCL]] knows what distance to keep.
1036937
1037938- FBoundsRectForNewParent: TRect
1038939
1039940When changing the Parent of a control the Handle is recreated and many things can happen. Especially for docking forms the process is too unreliable. Therefore the BoundsRect is saved. The VCL uses a similar mechanism.
1040941
1041942- fLastAlignedBounds: TRect
1042943
1043944See TControl.SetAlignedBounds for an explanation. In short: It stops some circles between interface and [[LCL]] autosizing.
1044945
1045946- FLastChangebounds: TRect
1046947
1047948Used to stop calling ChangeBounds with the same coordinates. This happens very often.
1048949
1049950- FLastDoChangeBounds: TRect
1050951
1051952Used to avoid calling OnChangeBounds with the same coordinates. This reduces user defined autosizing.
1052953
1053954- FLastResizeClientHeight: integer
1054955- FLastResizeClientWidth: integer
1055956- FLastResizeHeight: integer
1056957- FLastResizeWidth: integer
1057958
1058959Used to avoid calling OnResize with the same coordinates. This reduces user defined autosizing.
1059960
1060961- FLoadedClientSize: TPoint
1061962
1062963During loading many things are delayed and many things are set and worse: in the wrong order. That's why SetClientWidth/SetClientHeight calls are stored and set at end of loading again. This way the [[LCL]] can restore the distances (e.g. akRight) used during designing.
1063964
1064965- FReadBounds: TRect
1065966
1066967Same as FLoadedClientSize, but for SetLeft, SetTop, SetWidth, SetHeight.
1067968
1068969- procedure SetBoundsRectForNewParent(const AValue: TRect);
1069970
1070971Used to set FBoundsRectForNewParent. See above.
1071972
1072973- procedure SetAlignedBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
1073974
1074975As SetBounds but without changing the default sizes.
1075976
1076977- procedure SetInitialBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
1077978
1078979A smart version of SetBounds, reducing overhead during creation and loading.
1079980
1080981- procedure UpdateBaseBounds(StoreBounds, StoreParentClientSize, UseLoadedValues: boolean); virtual;
1081982
1082983Commit current bounds to base bounds.
1083984
1084985- procedure SetClientHeight(Value: Integer);
1085986- procedure SetClientSize(Value: TPoint);
1086987- procedure SetClientWidth(Value: Integer);
1087988
1088989Exists for Delphi compatibility too. Resizes the control, to get the wanted ClientRect size.
1089990
1090991- procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
1091992
1092993This is the internal SetBounds. Applies constraints, updates base bounds, calls OnChangeBound, OnResize, locks bounds.
1093994
1094995- procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
1095996
1096997This really sets the FLeft, FTop, FWidth, FHeight private variables.
1097998
1098999- procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
10991000
11001001This is the standard procedure overriden by many Delphi controls. TWinControl overrides it too.
11011002
11021003- - ignores calls when bounds are locked
11031004 - lock the FBoundsRealized to avoid overhead to the interface during auto sizing.
11041005
11051006ChangeBounds is not locked this way.
11061007
11071008- Function GetClientOrigin: TPoint; virtual;
11081009
11091010Screen coordinate of Left, Top of client area.
11101011
11111012- Function GetClientRect: TRect; virtual;
11121013
11131014Size of client area. (always Left=0, Top=0)
11141015
11151016- Function GetScrolledClientRect: TRect; virtual;
11161017
11171018Visible client area in ClientRect.
11181019
11191020- function GetChildsRect(Scrolled: boolean): TRect; virtual;
11201021
11211022Returns the Client rectangle relative to the control's Left, Top. If Scrolled is true, the rectangle is moved by the current scrolling values (for an example see TScrollingWincontrol).
11221023
11231024- function GetClientScrollOffset: TPoint; virtual;
11241025
11251026Returns the scrolling offset of the client area.
11261027
11271028- function GetControlOrigin: TPoint; virtual;
11281029
11291030Returns the screen coordinate of the topleft coordinate 0,0 of the control area. (The topleft pixel of the control on the screen) Note that this value is the position as stored in the interface and is not always in sync with the [[LCL]]. When a control is moved, the [[LCL]] sets the bounds to the wanted position and sends a move message to the interface. It is up to the interface to handle moves instantly or queued.
11301031
11311032## FAQ
11321033
11331034### Why does AutoSize not work in the designer properly?
11341035
11351036In the designer controls can be dragged around and properties can be set in almost any order. To allow this and avoid possible conflicts, the AutoSizing is not updated on every change at design time.
11361037
11371038### Why does TForm.AutoSize not work when something changes?
11381039
11391040See [[Autosize / Layout|AutoSize and Forms]]
11401041
11411042### Do I need to call Application.ProcessMessages when creating lots of controls?
11421043
11431044Application.ProcessMessages is called by the [[LCL]] automatically after every message (e.g. after every event like OnClick). Calling it yourself is only needed if the changes should become visible to the user immediately. For example:
11441045
11451046``` pascal
11461047procedure TFrom.Button1Click(Sender: TObject);
11471048begin
11481049 // change width of a control
11491050 Button1.Width := Button1.Width + 10;
11501051 // apply any needed changes and repaint the button
11511052 Application.ProcessMessages;
11521053 // do a lot of things that takes a long time
11531054 ...
11541055 // after leaving the OnClick the LCL automatically processes messages
11551056end;
11561057```
11571058
11581059### When enabling Anchors at runtime the control resizes, does not use the current values. Why?
11591060
11601061akBottom means: keep a distance to the bottom side of the parent. The distance to keep is defined by the base bounds. They are set at designtime or by runtime calls of SetBounds or UpdateBaseBounds.
11611062
11621063For example: A TListBox (Anchors=\[akLeft,aTop\]) at designtime has a bottom distance of 100 pixel. And a button to enable/disable the akBottom of the TListBox. Now start the application and press the button to enable akBottom. The 100 pixel distance will be activated, because this was the last time the programmer defined the base bounds of the TListBox. All other resizes were done by the [[LCL]] and are irrelevant. The programmers base bounds rules. You can resize the form and the 100 pixel will be kept. In order to use the current bounds as base bounds use:
11631064
11641065``` pascal
11651066ListBox1.UpdateBaseBounds(true, true, false);
11661067ListBox1.Anchors := ListBox1.Anchors + [akBottom];
11671068```
11681069
11691070Setting Anchors does not automatically call UpdateBaseBounds, because this would destroy the ability to change properties independently.
11701071
11711072### Resizing stringgrid columns in form's OnResize event does not work
11721073
11731074The Form's OnResize is triggered when the Form's Width, Height, ClientWidth or ClientHeight changes. This is per se independent of TStringGrid. Of course it often happens that both the Form and the TStringGrid are resized. This means using forms OnResize will often work, but not always. A prominent example where it always fails is when the theme is changed and you have a TStringGrid in a TGroupBox in a TForm. When the theme changed the form size is kept, so no Forms OnResize is triggered. But the TGroupBox changed, so the TStringGrid should be resized.
11741075
11751076Solution: Use the TStringGrid's OnResize.
11761077
11771078### Why is TForm.Width equal to TForm.ClientWidth?
11781079
11791080Mattias' notes:
11801081
11811082"There are historical and technical reasons.
11821083
11831084For forms without parent the Clientwidth equals the Width, because the real Width including the frame was not available on Linux ten years ago (at least not reliable on various window managers). I didn't test, but I heard it is now possible with gtk2. The main problem is the autosizing, because this needs the frame sizes before the form is mapped to the screen. It might be, that this is only available after an event, which means that you have to wait for it, which means trouble for ShowModal. Changing this breaks compatibility with a lot of existing [[LCL]] code, but for this we added the LCLVersion in the lfm files.
11841085
11851086There is a new compiler define **LCLRealFormBounds** In Lazarus trunk 1.7 that enables real size for a form. To use it just compile your application with LCLRealFormBounds ON. For now, only win32 widget set is supported.
11861087
11871088For all other controls the rules is ClientWidth\<=Width. The Width is the ClientWidth plus the widget frame. The question is if the scrollbars belong to the frame. I would say yes and it was implemented that way some time ago. Apparently this has changed. See the current cursor problem on synedit."
11881089
11891090### I get an infinite loop / How to debug autosizing?
11901091
11911092Here are some notes, describing what other users did wrong and how to find out:
11921093
11931094#### Differences to Delphi
11941095
11951096For Delphi users: Please read: [[Autosize / Layout|Lazarus_vs_Delphi]]
11961097
11971098#### Overriding a [[LCL]] method and triggering a recompute
11981099
11991100You override a method and tell the [[LCL]] to compute again, even if nothing changed. Check for AdjustSize, Realign, AlignControls, InvalidatePreferredSize. For example:
12001101
12011102``` pascal
12021103procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
12031104begin
12041105 // This will create an endless loop
12051106 InvalidatePreferredSize;
12061107
12071108 // This will create an endless loop too:
12081109 OtherComponent.Left:=10;
12091110 OtherComponent.Left:=20;
12101111
12111112 inherited SetBounds(ALeft, ATop, AWidth, AHeight);
12121113end;
12131114```
12141115
12151116Explanation: The SetBounds method is called often, even without changing anything. For example a "Left:=30;" will do so.
12161117
12171118Remedy: Check for changes:
12181119
12191120``` pascal
12201121procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
12211122begin
12221123 if (Left <> ALeft) or (Top <> ATop) or (Width <> AWidth) or (Height <> AHeight) then
12231124 InvalidatePreferredSize;
12241125 inherited SetBounds(ALeft, ATop, AWidth, AHeight);
12251126end;
12261127```
12271128
12281129##### TWinControl.AlignControls
12291130
12301131``` pascal
12311132procedure AlignControls(aControl: TControl; var aRect: TRect); override;
12321133```
12331134
12341135AlignControls moves and sizes all child controls. The [[LCL]] implementation ignores controls with Align=alCustom.
12351136
12361137The parameter aControl: TControl is kept for VCL compatibility. The [[LCL]] always passes nil. It gives aControl precedence when applying the Align property. When you have for example two controls A,B with Align=alLeft then the one with the lower Left is put left most. If both have the same Left then creation order wins. Now imagine you want to switch both controls A,B in the designer. You drag B to the left. This results in setting B.Left to 0. Now AlignControls starts and find both A.Left=0 and B.Left=0. Normally A would win. To let B win the VCL calls AlignControls(B,r). So aControl is the last moved. Contrary to the VCL the [[LCL]] allows to combine multiple layout changes without recomputing on every step. The [[LCL]] keeps track of the last moved controls in TWinControl.fAlignControls and applies the order in TWinControl.CreateControlAlignList. The aControl parameter is always nil.
12371138
12381139See TWinControl.CreateControlAlignList.
12391140
12401141#### OnResize/OnChangeBounds conflict with [[LCL]] properties
12411142
12421143You set bounds that bite the [[LCL]] properties. For example a TLabel.AutoSize is true by default. If you set the Label1.Width in an OnResize event, the [[LCL]] will recompute, resize the Label1 and call the OnResize again. Start your application in the debugger and reproduce the bug. When it enters the loop, pause the application and see the call stack. If you see one of your events or your methods start searching there. For example:
12431144
12441145``` pascal
12451146procedure TMainForm.FormResize(Sender: TObject);
12461147begin
12471148 // if Button1 is anchored or AutoSize=true then the following might create an endless loop:
12481149 Button1.Width:=100;
12491150end;
12501151```
12511152
12521153#### [[LCL]] interface bug, custom widget
12531154
12541155Sometimes the [[LCL]] interface or your custom control has a bug and undoes the [[LCL]] bounds. Compile the [[LCL]] with -dVerboseIntfSizing. This will write the communication between [[LCL]] and the [[LCL]] interface. If a widget does not allow free resizing, it must tell the [[LCL]] via the Constraints. Search for SetInterfaceConstraints in the various [[LCL]] interfaces and TWSControlClass.ConstraintWidth/Height.
12551156
12561157#### alCustom
12571158
12581159You use alCustom. This was only half implemented in earlier Lazarus versions, but some clever programmers used it to create some special effects. Now it is implemented and your program does not work anymore. Please see here what alCustom does: [[Autosize / Layout|alCustom]].
12591160
12601161## See also
12611162
12621163- [[Docking]]
12631164- [[High DPI]]
12641165- [[Anchor Sides]]
12651166
12661167---
12671168*From the Free Pascal wiki, page "Autosize / Layout", as it stood on 2021-04-13 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history