Sign in Join
Wiki copytemporary

Anchor Sides: what changed

Revision 1 to 2. 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
77`+--------+ +-------+`\
88`| Label1 | | Edit1 |`\
99`+--------+ |       |`\
1010`           +-------+`
1111
1212### In code
1313
1414``` Pascal
1515Edit1.AnchorSide[akLeft].Side := asrRight;
1616Edit1.AnchorSide[akLeft].Control := Label1;
1717Edit1.Anchors := Edit1.Anchors + [akLeft];
1818```
1919
2020You can define the distance with the BorderSpacing properties:
2121
2222``` Pascal
2323Edit1.BorderSpacing.Left := 10;
2424```
2525
2626The same can be done with the method:
2727
2828``` Pascal
2929Edit1.AnchorToNeighbour(akLeft, 10, Label1);
3030```
3131
3232### Notes
3333
3434The 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]].
3535
3636### Via the Anchor Editor
3737
3838The 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.
3939
40-<figure>
41-<img src="Anchor_Editor_en.png" title="Anchor_Editor_en.png" />
42-<figcaption>Anchor_Editor_en.png</figcaption>
43-</figure>
40+![](/wiki-images/2/28/Anchor_Editor_en.png)
4441
4542## Example 2
4643
4744You can anchor the Edit's top side to follow the Label's top side:
4845
4946 +--------+ +-------+
5047 | Label1 | | Edit1 |
5148 +--------+ | |
5249 +-------+
5350
5451``` Pascal
5552Edit1.AnchorSide[akTop].Side := asrTop;
5653Edit1.AnchorSide[akTop].Control := Label1;
5754Edit1.Anchors := Edit1.Anchors + [akTop];
5855```
5956
6057The same can be done with the method:
6158
6259``` Pascal
6360Edit1.AnchorParallel(akTop,0,Label1);
6461```
6562
6663## Example 3
6764
6865Centering a Label vertically to an Edit:
6966
7067 +-------+
7168 +--------+ | |
7269 | Label1 | | Edit1 |
7370 +--------+ | |
7471 +-------+
7572
7673``` Pascal
7774Edit1.AnchorSide[akTop].Side := asrCenter;
7875Edit1.AnchorSide[akTop].Control := Label1;
7976Edit1.Anchors := Edit1.Anchors + [akTop] - [akBottom];
8077```
8178
8279The same can be done with the method:
8380
8481``` Pascal
8582Edit1.AnchorVerticalCenterTo(Label1);
8683```
8784
8885Obviously anchoring the bottom side of Edit1 does not make sense when centering.
8986
9087## Example 4
9188
9289Using 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`.
9390
9491- 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`.
9592- In the anchor editor do the following adjustments:
9693 - Anchor the top and bottom sides of the panels and the splitter to the corresponding sides of the form.
9794 - 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.
9895 - 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.
9996 - 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.
10097
10198The same effect can be achieved by this code:
10299
103100``` pascal
104101procedure TForm1.FormCreate(Sender: TObject);
105102begin
106103 with Panel1 do
107104 begin
108105 AnchorSideTop.Control := Self;
109106 AnchorSideBottom.Control := Self;
110107 AnchorSideBottom.Side := asrBottom;
111108 AnchorSideLeft.Control := Self;
112109 AnchorSideRight.Control := Splitter1;
113110 Anchors := [akLeft, akRight, akTop, akBottom];
114111 end;
115112 with Panel2 do
116113 begin
117114 AnchorSideTop.Control := Self;
118115 AnchorSideBottom.Control := Self;
119116 AnchorSideBottom.Side := asrBottom;
120117 AnchorSideLeft.Control := Splitter1;
121118 AnchorSideLeft.Side := asrBottom;
122119 AnchorSideRight.Control := self;
123120 AnchorSideRight.Side := asrBottom;
124121 Anchors := [akLeft, akRight, akTop, akBottom];
125122 end;
126123 with Splitter1 do
127124 begin
128125 AnchorSideTop.Control := Self;
129126 Splitter1.AnchorSideBottom.Control := Self;
130127 AnchorSideBottom.Side := asrBottom;
131128 Anchors := [akTop, akBottom];
132129 end;
133130end;
134131```
135132
136133## New property
137134
138135``` Pascal
139136property AnchorSide[Kind: TAnchorKind]: TAnchorSide read GetAnchorSide;
140137```
141138
142139This 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).
143140
144141## New methods to easily configure common layouts
145142
146143``` Pascal
147144procedure AnchorToNeighbour(Side: TAnchorKind; Space: integer; Sibling: TControl);
148145procedure AnchorParallel(Side: TAnchorKind; Space: integer; Sibling: TControl);
149146procedure AnchorHorizontalCenterTo(Sibling: TControl);
150147procedure AnchorVerticalCenterTo(Sibling: TControl);
151148procedure AnchorAsAlign(TheAlign: TAlign; Space: Integer);
152149```
153150
154151AnchorVerticalCenterTo works with Parent too. Then it will center on the client area, that means the center of the control is at *ClientHeight div 2*.
155152
156153Center 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\]).
157154
158155## Anchoring to invisible controls
159156
160157Anchoring 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):
161158
162159` +---+ +---+ +---+`\
163160` | A | | B | | C |`\
164161` +---+ +---+ +---+`
165162
166163If B is hidden (Visible:=[[False|false]]) then C.Left will skip B and use the right of A, resulting in
167164
168165` +---+ +---+`\
169166` | A | | C |`\
170167` +---+ +---+`
171168
172169## Circular references
173170
174171You 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.
175172
176173There 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
177174
178175``` Pascal
179176Parent.DisableAutosizing;
180177try
181178 // change anchors, aligns, bounds...
182179finally
183180 Parent.EnableAutosizing;
184181end;
185182```
186183
187184The AutoSize algorithm does not only break circles, but fixes Align/AnchorSide inconsistencies too.
188185
189186Eventually it would be good to add some hints in the designer or a tool to list the circles and inconsistencies.
190187
191188## See also
192189
193190- [[Autosize / Layout]]
194191- [[Example: Anchors. How to reliably align dynamically created controls under changing visibility]]
195192
196193---
197194*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