Sign in Join
Wiki copytemporary

Anchor Sides: what changed

Revision 3 to 4. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11There are some new [[Property|properties]] and [[Method|methods]] for automatic layout of controls. You can now setup controls to keep a certain distance to other controls, or center relative to other controls. See below for examples.
22
33Each of the four sides of a control (Left, Top, Right, Bottom) can now be anchored/bound to a side of another control. For example you can now anchor the left side of [[TEdit]] to the right side of a [[TLabel]]. Everytime the Label is moved or resized the Edit's left side will follow, which normally results in moving the Edit parallel to the Label.
44
55## Example 1
66
7-```
7+```text
88+--------+ +-------+
99| Label1 | | Edit1 |
1010+--------+ | |
1111 +-------+
1212```
1313
1414### In code
1515
1616``` Pascal
1717Edit1.AnchorSide[akLeft].Side := asrRight;
1818Edit1.AnchorSide[akLeft].Control := Label1;
1919Edit1.Anchors := Edit1.Anchors + [akLeft];
2020```
2121
2222You can define the distance with the BorderSpacing properties:
2323
2424``` Pascal
2525Edit1.BorderSpacing.Left := 10;
2626```
2727
2828The same can be done with the method:
2929
3030``` Pascal
3131Edit1.AnchorToNeighbour(akLeft, 10, Label1);
3232```
3333
3434### Notes
3535
3636The Edit1.Left will follow Label1.Left+Label1.Width, not the other way around. That means, moving Label1 will move Edit1. But moving Edit1 will be undone by the [[LCL]]. If you also anchor the right side of Label1 to the left side of Edit1, you created a circle, and this can result together with some other autosize properties in a loop. This is ignored by the LCL or automagically repaired when the Parent.AutoSize is [[True|true]].
3737
3838### Via the Anchor Editor
3939
4040The anchor editor is a floating window that is available via the menu **View / Anchor Editor** or via the button on the **Anchors** property in the object inspector.
4141
4242![](/wiki-images/2/28/Anchor_Editor_en.png)
4343
4444## Example 2
4545
4646You can anchor the Edit's top side to follow the Label's top side:
4747
4848 +--------+ +-------+
4949 | Label1 | | Edit1 |
5050 +--------+ | |
5151 +-------+
5252
5353``` Pascal
5454Edit1.AnchorSide[akTop].Side := asrTop;
5555Edit1.AnchorSide[akTop].Control := Label1;
5656Edit1.Anchors := Edit1.Anchors + [akTop];
5757```
5858
5959The same can be done with the method:
6060
6161``` Pascal
6262Edit1.AnchorParallel(akTop,0,Label1);
6363```
6464
6565## Example 3
6666
6767Centering a Label vertically to an Edit:
6868
6969 +-------+
7070 +--------+ | |
7171 | Label1 | | Edit1 |
7272 +--------+ | |
7373 +-------+
7474
7575``` Pascal
7676Edit1.AnchorSide[akTop].Side := asrCenter;
7777Edit1.AnchorSide[akTop].Control := Label1;
7878Edit1.Anchors := Edit1.Anchors + [akTop] - [akBottom];
7979```
8080
8181The same can be done with the method:
8282
8383``` Pascal
8484Edit1.AnchorVerticalCenterTo(Label1);
8585```
8686
8787Obviously anchoring the bottom side of Edit1 does not make sense when centering.
8888
8989## Example 4
9090
9191Using a [[TSplitter]] with the AnchorEditor between two panels: the left panel should behave as if it had `Align=alLeft`, the right panel should behave as if it had `Align=alClient`.
9292
9393- Do not use the `Align` properties of the panels and of the splitter. They must be set to `alNone`. This is important for the splitter for which the default value is `alLeft`.
9494- In the anchor editor do the following adjustments:
9595 - Anchor the top and bottom sides of the panels and the splitter to the corresponding sides of the form.
9696 - Select the first panel and anchor its left side to the left side of the form and its right side to the left side of the splitter.
9797 - Select the second panel and anchor its right side to the right side of the form and its left side to the right side of the splitter.
9898 - The left and right sides of the splitter must not be anchored (as seen from the splitter itself) because this would fix the position of the splitter and make it not movable.
9999
100100The same effect can be achieved by this code:
101101
102102``` pascal
103103procedure TForm1.FormCreate(Sender: TObject);
104104begin
105105 with Panel1 do
106106 begin
107107 AnchorSideTop.Control := Self;
108108 AnchorSideBottom.Control := Self;
109109 AnchorSideBottom.Side := asrBottom;
110110 AnchorSideLeft.Control := Self;
111111 AnchorSideRight.Control := Splitter1;
112112 Anchors := [akLeft, akRight, akTop, akBottom];
113113 end;
114114 with Panel2 do
115115 begin
116116 AnchorSideTop.Control := Self;
117117 AnchorSideBottom.Control := Self;
118118 AnchorSideBottom.Side := asrBottom;
119119 AnchorSideLeft.Control := Splitter1;
120120 AnchorSideLeft.Side := asrBottom;
121121 AnchorSideRight.Control := self;
122122 AnchorSideRight.Side := asrBottom;
123123 Anchors := [akLeft, akRight, akTop, akBottom];
124124 end;
125125 with Splitter1 do
126126 begin
127127 AnchorSideTop.Control := Self;
128128 Splitter1.AnchorSideBottom.Control := Self;
129129 AnchorSideBottom.Side := asrBottom;
130130 Anchors := [akTop, akBottom];
131131 end;
132132end;
133133```
134134
135135## New property
136136
137137``` Pascal
138138property AnchorSide[Kind: TAnchorKind]: TAnchorSide read GetAnchorSide;
139139```
140140
141141This is not published in the [[IDE Window: Object Inspector|object inspector]]. You can edit it in the designer via the [[IDE Window: Anchor Editor|anchor editor]] (Menu: View -\> View anchor editor, or click on button of 'Anchors' property).
142142
143143## New methods to easily configure common layouts
144144
145145``` Pascal
146146procedure AnchorToNeighbour(Side: TAnchorKind; Space: integer; Sibling: TControl);
147147procedure AnchorParallel(Side: TAnchorKind; Space: integer; Sibling: TControl);
148148procedure AnchorHorizontalCenterTo(Sibling: TControl);
149149procedure AnchorVerticalCenterTo(Sibling: TControl);
150150procedure AnchorAsAlign(TheAlign: TAlign; Space: Integer);
151151```
152152
153153AnchorVerticalCenterTo works with Parent too. Then it will center on the client area, that means the center of the control is at *ClientHeight div 2*.
154154
155155Center anchoring is not yet fully supported when computing the size of the parent. For example when you put a label center anchored into a [[TGroupBox|Groupbox1]] and set Groupbox1.AutoSize to true then Groupbox1 height will shrink leaving no space for the label. The solution is to center to a control that is not centered. For example center a Label1 to a [[TComboBox|ComboBox]] and use for the ComboBox the default anchors (Anchors=\[akLeft,akTop\]).
156156
157157## Anchoring to invisible controls
158158
159159Anchoring to invisible controls works intuitively. For example: The below controls A, B, C are anchored (C.Left to B.Right and B.Left to A.Right):
160160
161-```
161+```text
162162 +---+ +---+ +---+
163163 | A | | B | | C |
164164 +---+ +---+ +---+
165165```
166166
167167If B is hidden (Visible:=[[False|false]]) then C.Left will skip B and use the right of A, resulting in
168168
169-```
169+```text
170170 +---+ +---+
171171 | A | | C |
172172 +---+ +---+
173173```
174174
175175## Circular references
176176
177177You can build circular references by anchoring two sides to each other, which creates an impossible anchoring. The LCL notices that, but will not raise an exception, because it can be a temporary circle. For example: A row of buttons. Button1 is left of Button2, Button2 is left of Button3. Now the order is changed to: Button3, Button1, Button2. If the reanchoring is started with Button3, a circle is created temporarily and is fixed when the reordering is completed. The LCL detects circles and will not move the Button. Circles are not the only anomaly.
178178
179179There is one exception to this rule. If the Parent.AutoSize is true, then the LCL will automatically break circles on autosize and writes a warning via [[DebugLn|debugln]] (windows: --debug-log.txt, linux, et al: stdout). Which anchor is broken depends on the order of controls and the sides. So, temporary circles are still allowed with AutoSize=true if you enclose the change in
180180
181181``` Pascal
182182Parent.DisableAutosizing;
183183try
184184 // change anchors, aligns, bounds...
185185finally
186186 Parent.EnableAutosizing;
187187end;
188188```
189189
190190The AutoSize algorithm does not only break circles, but fixes Align/AnchorSide inconsistencies too.
191191
192192Eventually it would be good to add some hints in the designer or a tool to list the circles and inconsistencies.
193193
194194## See also
195195
196196- [[Autosize / Layout]]
197197- [[Example: Anchors. How to reliably align dynamically created controls under changing visibility]]
198198
199199---
200200*From the Free Pascal wiki, page "Anchor Sides", as it stood on 2021-10-11 after a change by Kai Burghardt, 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