Sign in Join
Wiki copytemporary

Autosize / Layout/zh CN: what changed

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

OldNewLine
11# 概述
22
33[[LCL]]可以自动修改一个控件的大小和位置,以便它适应字体,主题和文本或者其它内容的更改。如果你想在一些平台上运行你的 程序,或者你的标题可以使用一些语言,你的控件需要适应它们的当前环境。[[LCL]]不仅允许你做一次快速设计(使用鼠标在一个窗体上到处移动控件) ,并且后期设置一些将使控件随后自动地适应更改控件的关键属性等等。
44
55- 固定设计:这是在设计器中放置一个控件的默认设置。控件的位置相对其父类控件是固定的。控件的大小和位置(左,顶)可由程序员完全调整。你可以使用鼠标四处移动控件,和自由重新调整其大小。
66- 对齐:对齐的控件将填充剩余父类控件空间顶部、底部、左侧和右侧,或者填充整个剩余空间。
77- 锚:你可以锚定一个控件的边侧(左,顶,右,底)到它的父类组件或到另一个组件。锚定的意思:[[LCL]]将尝试维持与锚定点相同的距离。
88- 布局:控件可以在行和列中自动地对齐 (例如, TRadioGroup)
99- 通过OnResize自定义:你可以在代码中使用OnResize和OnChangeBounds事件来对齐你自己的控件。
1010- 自定义控件:写你自己的控件,你可以重写(override)几乎任何你想的[[LCL]]行为。
1111
1212## 优先级规则
1313
14141. 约束式(Constraints)
15152. 对齐(Align)
16163. 锚(Anchors)
17174. 子控件大小.布局(ChildSizing.Layout)
18185. 自动大小(AutoSize)
19196. OnResize, OnChangeBounds - 但是,如果你设置与上述规则冲突的边界,你将创建一个死循环。
2020
2121## 公共属性
2222
2323可以更改一些重要的属性来配置自动大小:
2424
2525- Left, Top, Width, Height(左,顶,宽,高)
2626- 自动大小(AutoSize):autosize通知[[LCL]]自动地重新调整一个控件的宽度和高度。
2727- 锚(Anchors):让你创建依赖关系/附属关系,例如,来锚一个ComboBox到一个Label的右侧。
2828- 对齐(Align)
2929- 约束式(Constraints):让你为宽度和高度设置一个最小值和最大值。
3030- 边界空格(BorderSpacing): 让你设置锚定控件之间的空格。
3131- ChildSizing:让你设置子控件的布局和空格。
3232
3333内部算法在这里解释:[[LCL自动大小(AutoSizing)]]。
3434
3535# 固定设计
3636
3737固定设计是默认的。控件的属性设置为\[akLeft,akTop\],这意味着左侧和顶部的值没有被[[LCL]]更改。如果AutoSize的值是false,[[LCL]]不改变宽度或高度。如果AutoSize的值是true,宽度 和高度将被更改以适应内容。例如,TLabel.AutoSize默认值为true,因此将更改它的标题来将重新调整 label 大小以容纳更改的表达方式。TButton.AutoSize默认值是false,因此更改一个按钮的标题不会重新调整按钮大小。当你设置Button.AutoSize为true时,每次更改按钮的标题或它的字体(或主体),按钮将收缩或放大。注意,这些更改不总是立即发生的。例如,在FormCreate期间,所有的自动大小是挂起的。无论何时,你都可以更改"Left", "Top", "Width",或"Height"属性。
3838
3939# 自动大小(AutoSize)
4040
4141`AutoSize`是一个在很多类中可用找到的布尔值属性;它允许自动地调整一个控件的大小以适应顾及所含文本或图形的差异,也允许最有效地使用可用空间。这是创建跨平台窗体的关键机制。 通常地, AutoSize=true 对一个可视控件做两件事:
4242
4343- 如果有可能,它将重新调整控件的大小为首选大小。例如,一个TButton的宽度和高度被重新调整大小以适应标题,在一个TEdit仅在高度上重新调整大小的同时。一个TEdit的宽度不被自动大小。你可以更改一个TEdit的宽度。(查看GetPreferredSize)。
4444- 它以相同的数量移动固定位置的子控件,以便最左侧的子控件移动到 Left=0 (取决于边界空格(BorderSpacing)),最顶部的子控件移动到 Top=0 。
4545
4646## Lazarus vs Delphi
4747
4848- Delphi的自动大小(AutoSize)仅当某些属性更改时发生,例如,当一个TLabel的字体更改时。[[LCL]]的自动大小(AutoSize)总是激活的。Delphi允许更改一个有AutoSize=true的Lable的大小, 而Lazarus控件不允许。
4949- Delphi的隐藏的控件不会被自动大小。
5050- 使用Delphi,在加载期间,更改一个控件的大小不会重新调整大小/移动锚定子控件,但是一个构造函数通常被用来制作预期效果。当使用akRight,akBottom锚时,设置AnchorSides(锚定边)和BorderSpacing(边界空格)以保持距离正确。
5151
5252## 自动大小(AutoSize)和重新调整大小控件
5353
5454使用AutoSize=false,按钮将给予一个默认的固定大小。
5555
5656![](/wiki-images/1/1f/Autosize1.png)
5757
5858当为每个按钮设置 AutoSize=true 时,按钮将放大(或收缩)以适应文本和主题框架。
5959
6060![](/wiki-images/7/75/Autosize_on.png)
6161
6262正如你在OK按钮中所见,AutoSize不会收缩到最小可能的尺寸大小。它使用控件的 GetPreferredSize方法,该方法调用CalculatePreferredSize方法。默认的TWinControl实施询问 widget集合,这可能有一个首选的宽度或高度。每个控件都可以重写(override) CalculatePreferredSize 方法。例如,TImage 重写(override)它,并返回图片的大小。如果没有可用的首选的宽度(高度),返回的值是0,并且[[LCL]]将保持宽度(高度) (除非ControlStyle设置标示csAutoSize0x0,当前仅TPanel使用)。
6363
6464一个TWinControl计算其所有子控件的大小,并使用它来计算首选大小。
6565
6666当一个控件被锚定到左侧和右侧,并且它的 宽度 是固定的。例如,使用 Align=alTop ,控件被锚定到左侧和右侧,并且沿袭父类控件的宽度。如果 Parent.AutoSize 为 true,那么 Parent 将使用控件的首选宽度来计算它自身的首选宽度,以此方式,控件将重新调整大小为它的首选宽度。查看 [[Autosize / Layout/zh CN|对齐和自动大小(AutoSize]]. 如果没有 可用的首选宽度,那么最后设置的边界将被使用(BaseBounds或ReadBounds)。 如果没有边界被设置,GetControlClassDefaultSize方法将被使用。Same for对于高度和锚定到顶部和底部是一样的。
6767
6868约束式总是被应用,并且有优先权。
6969
7070## 自动大小 (AutoSize)和移动子控件
7171
7272当 AutoSize=false 时,你可以自由地放置和移动控件:
7373
7474![](/wiki-images/7/75/Autosize_on.png)
7575
7676当 AutoSize=true 时,有固定位置的子控件将移动以适应位置。
7777
7878![](/wiki-images/d/d9/Autosize_panel_on.png)
7979
8080在面板上是所有按钮都将通过相同的数量来移动到顶部和左侧,以便左侧和顶部没有剩余的空间。如果按钮可能有 BorderSpacing\>0 或 Panel.ChildSizing.LeftRightSpacing\>0 ,按钮可能被移动,以便使用定 义的空格量
8181
8282仅具有下面值的子控件将被移动:
8383
8484- Anchors=\[akLeft,akRight\]
8585- AnchorSide\[akLeft\].Control=nil
8686- AnchorSide\[akTop\].Control=nil
8787- Align=alNone
8888
8989子控件的移动取决于属性[[Autosize / Layout|ChildSizing.Layout]]。 该布局被应用于方法 TWinControl.AlignControls ,这将完全重写或部分重写 (overridden)例如,TToolBar 重写 (overridden) ControlsAligned 到所有使用 Align=alCustom 的控件的位置,并定义一个流布局,在流布局中不适合的控件将被推放到后续的行中。
9090
9191控件可以通过设置ControlStyle标示csAutoSizeKeepChildLeft 和 csAutoSizeKeepChildTop (自0.9.29版本可用)来禁用子控件的移动。
9292
9393## 自动 大小(AutoSize)和窗体
9494
9595没有父类控件的窗体将被窗口管理器控制,因而不能自由地放置和重新调整大小。设置大小仅是一个建议,并且可能会被 窗口管理器忽略。例如,你可以设置一个窗体的宽度为1000, 而 widget集可能会重新调整大小为800作为回应。如果你在OnResize中设置宽度,你可能会创建一个死循环。这就是为什么当widget集重新设 置窗体大小时,[[LCL]] TForm 禁用自动大小(AutoSize)的原因。
9696
9797这意味着当用户重新调整窗体大小或假设窗口管理器不喜欢边界时,窗体的自动大小(AutoSize)将停止。例 如,一些Linux窗口管理器有参照关联的其它窗口重新调整该窗体的磁性边功能。
9898
9999### 强制一个窗体的自动大小
100100
101101你可以启动/执行一次新的自动大小(AutoSize),通过这样做:
102102
103103``` pascal
104104Form1.AutoSize := False;
105105Form1.AutoSize := True;
106106```
107107
108108### 预先计算一个自动大小的窗体的大小
109109
110110当放置一个自动大小的窗体时,你可能需要在显示该窗体前知道它的大小。自动大小需要句柄(handle)。你可以 在显示一个窗体前计算其大小,使用:
111111
112112``` pascal
113113Form1.HandleNeeded;
114114Form1.GetPreferredSize(PreferredWidth,PreferredHeight);
115115```
116116
117117**注意**: 窗口管理器和窗体事件可能会更改窗体大小。首先大小不包含窗体的窗口边界。这是一个计划中的功能。
118118
119119# 锚定边
120120
121121控件有四个边: akLeft, akTop, akRight 和 akBottom。每个边都能被锚定到父类控件或另一个同类控件(具有相同父类控件的一个控件)的边。锚意味着**保 存距离**。默认是 Anchors=\[akLeft,akTop\] 。垂直锚与水平锚互不干涉。像 Align 和 Parent.AutoSize 之类的一些的属性有较高的优先级,并可以更改行为。
122122
123123## 锚定到父类控件或锚定到空值
124124
125125锚定到空值(默认)与锚定到父类控件有几乎相同的效果。都尝试与父类控件客户端区域的一边保持距离。锚定到空值使 用最后的SetBounds调用距离,然而锚定到父类控件使用BorderSpacing值。
126126
127127这里有akLeft,akRight (akTop,akBottom)的四种组合:
128128
129129- **有akLeft,没有akRight**:控件的**左边**是固定的,不由 [[LCL]]更改。右边没有锚定,因此它跟随左边。这意味着,控件的**长度**也是保存不变的
130130- **有akLeft,有akRight**: 控件的**左边**是固定的。不由[[LCL]]更改。右边被锚定到父类控件的右边。这意味着,如果父类控件被放大 100pixel ,那么控件的**宽度**也被放大 100pixel 。
131131- **有akRight,没有akLeft**:控件的左边不是固定的,因此它将跟随它的右边。右边是 锚定的。这意味着,如果父类控件被放大 100pixel ,那么控件也将被向右移动 100pixel 。
132132- **没有akLeft.没有akRight**:两边都没有锚定。控件的中心的位置与父类控件一起缩 放。例如,如果控件在父类控件的中间,并且父类控件被放大 100 pixel ,那么控件将被向右移动 50pixel 。
133133
134134### 更改一个锚定的控件的父类控件的大小
135135
136136当更改一个父类控件的大小时,除非自动大小是禁用的,否则所有锚定的子控件也将被连立即移动和/或重新调整大小。 例如,在一个窗体的加载期间和在一个窗体的创建期间,自动大小是被禁用的。
137137
138138一个组框带有一个按钮: ![](/wiki-images/6/60/Anchors1.png)
139139
140140当组框被放大时,被锚定边的距离将保持不变:
141141
142142使用akLeft,不使用akRight: ![](/wiki-images/0/05/Anchors_akLeft.png)
143143
144144使用akLeft和akRight: ![](/wiki-images/6/66/Anchors_akLeft_akRight.png)
145145
146146使用akRight,不使用akLeft: ![](/wiki-images/d/d3/Anchors_akRight_no_akLeft.png)
147147
148148三个按钮在一个组框中: ![](/wiki-images/4/48/Anchors_no_akLeft_no_akRight_small.png)
149149
150150不使用akLeft和akRight,它们的中心被缩放: ![](/wiki-images/7/7b/Anchors_no_akLeft_no_akRight_big.png)
151151
152152**注释:**
153153
154154- 加载一个窗体像设置一大组边界。在加载期间,使用lfm的值设置属性。记住,因为原型和控件,这里可能有多 个lfm文件。在加载[[LCL]]启用自动大小后。锚定的控件使用在加载结束时边界。在中间的一些 步骤被忽略。
155155- 对于自定义控件,通常最好设置锚定侧而不是仅锚定。
156156
157157### 更改一个锚定控件的大小
158158
159159当更改一个锚定控件的宽度时,例如,通过对象查看器或通过代码 *Button1.Width:=3*, 你可以看到锚定到*父类控件* 和锚定到*空值*的不同点。锚定到父类控件将重新调整大小,并将移动Button1,然而锚定到空值将仅重新调整大小。例如:
160160
161161#### 锚定到空值
162162
163163![](/wiki-images/b/bd/Anchored_right_nil_resize1.png) 一个Button1锚定\[akTop,akRight\], AnchorSide\[akRight\].Control=nil
164164
165165![](/wiki-images/a/a0/Anchored_right_nil_resize2.png) 设置宽度到一个较小的值将收缩按钮,保持按钮的*左边*, 距离,减少按钮右边的距离。
166166
167167![](/wiki-images/1/16/Anchored_right_nil_resize3.png) 当组框被重新设置大小时,按钮也将保持新的距离。
168168
169169**img12:**设置**宽度**相当于调用SetBounds(SetBounds(**左侧**,顶部,**新宽度**,高度)。这就是为什么*左侧*距离被保持。这是与Delphi兼容的。
170170
171171#### 锚定到父类控件
172172
173173![](/wiki-images/4/45/Anchored_right_parent_resize1.png) 一个Button1锚定\[akTop,akRight\],AnchorSide\[akRight\].Control=Button1.Parent
174174
175175![](/wiki-images/0/04/Anchored_right_parent_resize2.png) 设置宽度到一个较小的值将收缩按钮,保持按钮的*右边*距离,减少按钮左边的距离。
176176
177177## 锚定到同级控件
178178
179179你可以锚定到相邻的控件,下面的示例显示:
180180
181181- 你可以锚定一个labe的左侧到一个按钮的左侧
182182- 锚定一个 label 的顶部到一个按钮的底部
183183- 锚定一个 label 的中心到一个按钮的中心
184184
185185![](/wiki-images/e/ee/Anchorsides_example1.png)
186186
187187![](/wiki-images/b/ba/Anchorside_example2.png)
188188
189189更多详细信息和如何设置锚,查看: [[锚定边]]。
190190
191191![](/wiki-images/4/4d/Anchoreditor2.png)
192192
193193## 边界空格
194194
195195边界空格(BorderSpacing)属性控制一个控件周围的最小空格量。属性是:
196196
197197- **Around(四周)**:这个量以像素为单位被添加到 左侧,顶部,右侧,底部。
198198- **Left(左侧)**:空格以像素为单位在控件的左侧
199199- **Top(顶部)**:空格以像素为单位在控件的顶部
200200- **Right(右侧)**:空格以像素为单位在控件的右侧l
201201- **Bottom(底部)**:空格以像素为单位在控件的底部
202202- **InnerBorder(内部边界)**: 这个量以像素为单位被两次添加到首先的宽度和高度。一些控件重写(override)计算并忽略这个属性。 TButton在这里就是一个工作的示例。使用InnerBorder,你可能使一个按钮比需要的大。
203203- **CellAlignHorizontal(单元格水平对齐)**:这被使用在表格中,像ChildSizing.Layout=cclLeftToRightThenTopToBottom。如果控件小于表格单元格,这 个属性定义控件对齐的位置:到左侧的ccaLeftTop,到右侧的ccaRightBottom,或子中间的 ccaCenter。
204204- **CellAlignVertical(单元格垂直对齐)**:类似于CellAlignHorizontal,但是由于垂直对齐。
205205
206206### 边界空格规则
207207
208208- Around被添加到左侧,顶部,右侧,底部边界空格
209209- 如果控件有不允许扩展的限制,则空格可能更大。
210210
211211#### 锚定到另一侧
212212
213213例如,A的右侧到B的左侧。
214214
215215A和B两者的边界空格都使用。
216216
217217- 在两控件(在父类控件上的LeftControl, RightControl)之间的最大水平空格是
218218 - LeftControl.BorderSpacing.Right + LeftControl.BorderSpacing.Around
219219 - RightControl.BorderSpacing.Left + RightControl.BorderSpacing.Around
220220 - Parent.ChildSizing.HorizontalSpacing
221221- 垂直空格工作类似:在两控件(在父类控件上的TopControl, BottomControl)之间的最大空格是
222222 - TopControl.BorderSpacing.Bottom + TopControl.BorderSpacing.Around
223223 - BottomControl.BorderSpacing.Top + BottomControl.BorderSpacing.Around
224224 - Parent.ChildSizing.VerticalSpacing
225225
226226例如,如果LeftControl.BorderSpacing.Right = 3 和 LeftControl.BorderSpacing.Around = 4,那么在两控件之间至少有7 pixel空格。如果RightControl.BorderSpacing.Left = 4 和 RightControl.BorderSpacing.Around = 4 ,那么空格将至少8。如果Parent.ChildSizing.HorizontalSpacing = 10,那么空格将至少是10。
227227
228228#### 锚定到同一侧
229229
230230例如,A的右侧到B的右侧。
231231
232232- 仅使用A的边界空格。
233233- Parent.ChildSizing.Horizontal/VerticalSpacing未被使用。
234234
235235#### 锚定到中心
236236
237237例如,A的中心到B的中心。
238238
239239未使用边界空格,未使用Parent.ChildSizing.Horizontal/VerticalSpacing 。
240240
241241#### 示例
242242
243243一个常见示例是锚定一个Label到一个Edit。
244244
245245![](/wiki-images/1/1e/BorderSpacing_Anchors.png)
246246
247247Label中心被垂直锚定到Edit。Edit的左边被锚定到Label的右边。两者都有 BorderSpacing.Around=6。这在Lable和Edit中间产生6个像素空格,Label的左侧 6个像素空格,Edit的右侧6个像素空格。也在Edit的上面和下面有6个像素空格。
248248
249249- 在一个控件和它的父类控件(Label1在GroupBox1上)的左侧空格最大值
250250 - Label1.BorderSpacing.Left + Label1.BorderSpacing.Around
251251 - GroupBox1.ChildSizing.LeftTopSpacing
252252
253253- 在一个控件和它的父类控件(Edit1在GroupBox1上)的右侧空格最大值
254254 - Edit1.BorderSpacing.Right + Edit1.BorderSpacing.Around
255255 - GroupBox1.ChildSizing.RightBottomSpacing
256256
257257- 当一个控件的中心被锚定到另一个控件时,例如,上述的Label于Edit1垂直居中,那么所有空格都被忽略。
258258
259259- 当一个控件的左侧被锚定到另一个控件的左侧时(例如,它们使用左侧对齐),那么两者左侧之间的距离是
260260 - Control1.BorderSpacing.Left + Control1.BorderSpacing.Around
261261
262262这里有一个更复杂的示例:
263263
264264![](/wiki-images/9/9c/Borderspacing_anchors2.png)
265265
266266lfm代码的重要部分:
267267
268-``` pascal
268+``` lfm
269269 object GroupBox1: TGroupBox
270270 AutoSize = True
271271 Caption = 'GroupBox1'
272272 TabOrder = 0
273273 object Label1: TLabel
274274 AnchorSideLeft.Control = GroupBox1
275275 AnchorSideTop.Control = Edit1
276276 AnchorSideTop.Side = asrCenter
277277 BorderSpacing.Around = 6
278278 Caption = 'Label1'
279279 end
280280 object Edit1: TEdit
281281 AnchorSideLeft.Control = Label1
282282 AnchorSideLeft.Side = asrBottom
283283 AnchorSideTop.Control = GroupBox1
284284 AnchorSideRight.Control = GroupBox1
285285 AnchorSideRight.Side = asrBottom
286286 Anchors = [akTop, akLeft, akRight]
287287 BorderSpacing.Around = 6
288288 TabOrder = 0
289289 Text = 'Edit1'
290290 end
291291 object Label2: TLabel
292292 AnchorSideLeft.Control = GroupBox1
293293 AnchorSideTop.Control = Edit1
294294 AnchorSideTop.Side = asrBottom
295295 BorderSpacing.Around = 6
296296 Caption = 'Label2'
297297 end
298298 object ComboBox1: TComboBox
299299 AnchorSideLeft.Control = Label2
300300 AnchorSideTop.Control = Label2
301301 AnchorSideTop.Side = asrBottom
302302 AnchorSideRight.Control = GroupBox1
303303 AnchorSideRight.Side = asrBottom
304304 Anchors = [akTop, akLeft, akRight]
305305 BorderSpacing.Right = 6
306306 TabOrder = 1
307307 Text = 'ComboBox1'
308308 end
309309 object CheckBox1: TCheckBox
310310 AnchorSideLeft.Control = GroupBox1
311311 AnchorSideTop.Control = ComboBox1
312312 AnchorSideTop.Side = asrBottom
313313 BorderSpacing.Around = 6
314314 Caption = 'CheckBox1'
315315 TabOrder = 2
316316 end
317317 object Label3: TLabel
318318 AnchorSideLeft.Control = GroupBox1
319319 AnchorSideTop.Control = Edit2
320320 AnchorSideTop.Side = asrCenter
321321 BorderSpacing.Around = 6
322322 Caption = 'Label3'
323323 end
324324 object Edit2: TEdit
325325 AnchorSideLeft.Control = Label3
326326 AnchorSideLeft.Side = asrBottom
327327 AnchorSideTop.Control = CheckBox1
328328 AnchorSideTop.Side = asrBottom
329329 BorderSpacing.Around = 6
330330 TabOrder = 3
331331 Text = 'Edit2'
332332 end
333333 end
334334```
335335
336336### 边界空格和对齐
337337
338338边界空格与对齐一起使用。在下面的示例中,这里有一个Memo1带有Align=alTop,和一个Memo2带有Align=alCLient。
339339
340340- 正常情况下,两个Memo将填充整个组框。
341341- 但是Memo1有BorderSpacing.Around=10, 所以在Memo1四周有10 pixel空间。
342342- Memo2有BorderSpacing.Top=20。在Memo1和Memo2之间的空间是最大的,是来自Memo2的2pixel空间。
343343- Memo2也有BorderSpacing.Right=50,所以在Memo2右侧有50pixel空间。
344344- 组框可以通过ChildSizing.LeftRightSpacing/VerticalSpacing /HorizontalSpacing为其所有的子控件定义默认空间。在这个示例中,它没有定义(全部是0)。
345345
346346![](/wiki-images/1/13/Borderspacing_align1.png)
347347
348348# 对齐
349349
350350Align属性的工作与Delphi非常相似,并且可用于快速填充一块区域。例如,来使一个TListBox填充 它的父类控件的整个区域,设置ListBox1.Align=alClient。如果有可能的话,align值 alTop, alBottom, alLeft 和 alRight 将不部分重叠地放置控件。这意味着,如果有足够的空间,所有的控件都将以alLeft,alTop,alBottom,alRight对齐而不会重叠。
351351
352352运算法则的工作如下:
353353
354354- 首先,所有使用alTop的控件被放到客户端区域的顶部。如果这里有使用alTop的控件,最后添加/移除 的的控件将被放到最上面。运算法则将尝试避免重叠和保持控件的高度,直到扩展宽度到最大值。忽略左侧,顶部和右 侧的锚定到侧。底部锚定到侧工作正常。Borderspacing和Parent.ChildSizing空间 被考虑,因此你可以定义每个对齐控件周围的空间。
355355- 然后,所有使用slBottom的控件被放置到客户端区域的底部。除此以外,它的工作方式类似于alTop。
356356- 然后,所有使用alLeft的控件被放置到在alTop和alBottom控件之间的客户端区域的左侧。除此以外,它的工作方式类似于alTop。
357357- 然后,所有使用alRight的控件被放置到在alTop和alBottom控件之间的客户端区域的右侧。除此以外,它的工作方式类似于alTop。
358358- 如果这里有一个使用alClient的控件,它将填充剩余的客户端。
359359- 如果这里有多个使用alClient的控件,它们将被放置到相同的位置,相互重叠。使用 Visibility属性来定义显示哪一个。
360360
361361![](/wiki-images/e/e6/Autosize_align.png)
362362
363363## 对齐和边界空格
364364
365365边界距离和父级控件的子控件大小的空间被应用于对齐控件。下面的memo有Align=alClient。
366366
367367![](/wiki-images/b/b4/Autosize_align_borderspacing.png)
368368
369369## 对齐和锚
370370
371371一个对齐控件的自由侧(例如,**Align=alLeft**的右侧)遵循锚定规则。如果未设置锚定,那么控件将保持它的**宽度**。如果设置锚定,那么宽度将更改。
372372
373373## 对齐和自动大小(AutoSize)
374374
375375一个使用alLeft或alRight对齐的控件垂直扩展,将使用它的设计宽度。如果*AutoSize*被 设置为*true*,那么*Width*将是首先宽度。下面的按钮有*Align=alRight*和*AutoSize=true*。
376376
377377![](/wiki-images/3/35/Autosize_align_autosize.png)
378378
379379## 对齐和父级控件自动大小(AutoSize)
380380
381381一个使用alClient对齐的控件将填充剩余的空间。一个使用*AutoSize=true* 的父类控件将扩展或收缩到精确的围住它的子控件。如果你组合两种属性将会发生什么?假设你放置一个使用Align=alClient的按钮到一个 AutoSize=true的组框中?
382382
383383![](/wiki-images/b/b1/Autosize_nested1.png)
384384
385385[[LCL]]使 用按钮的*首先大小*,相应地扩展或收缩组框:
386386
387387![](/wiki-images/2/28/Autosize_nested2.png)
388388
389389## alCustom(自定 义)
390390
391391这个对齐值存在于自定义自动大小(AutoSize)算法中,并且由[[LCL]]处理,差不多很像alNone。使用alCustom的控件不被[[LCL]]移动,而是由你的自定义控件移动。你必需重写(override) CalculatePreferredSize和DoAutoSize。
392392
393393## 使用相同对齐方式控件的顺序
394394
395395使用相同对齐方式控件按下面顺序放置。关于alLeft,使用最低的Left的控件获取,对于alTop,最低的 Top,对于alRight,最大的Left+Width,对于alBottom,最大的Top+Height。如 果两个控件有相同的坐标,最后移动的一个(调用SetBounds或SetParent)取胜。控件可以重写 (override ) CreateControlAlignList来更改顺序,或者重写(override) DoAlignChildControls来处理整个对齐方式。
396396
397397注意:在0.9.29之前,在同一坐标下的控件按Z顺序排列。在一些情况下,这导致了重新排序和不得不修复。这里 有一个不兼容的地方:如果你添加一些使用alTop或alLeft的控件,而没有具体指明限制范围,控件将被放置在 0,0处,因此最后添加的控件取胜,在这里前面的第一个控件取胜。
398398
399399Delphi用户注意: Delphi用户注意:与VCL相反,LCL可以并且经常延迟重新计算布局。Delphi在每次属性更改后都会进 行布局。在VCL中设置Align=alTop调用具体指明的AlignControls,在其中控件有一个具体指 明的意义。这就是为什么在VCL中设置属性的顺序很重要的原因。LCL布局算法与设置属性的时间顺序无关。
400400
401401例如,在FormCreate中的所有更改都会被延迟,并且布局是根据最终的属性值计算的。在另一方 面,ButtonClick没有延迟(也就是说,你必需自己添加Disable/EnableAutoSize), 因此插入alTop控件可能有不同的结果。
402402
403403如果你想要一个具体指定的顺序,使用Disable/EnableAutoSize,并设置"Top"属性。例 如,调用TForm.OnCreate时禁用AutoSize,所以你可以使用:
404404
405405``` pascal
406406procedure TForm1.FormCreate(Sender: TObject);
407407begin
408408 // making sure Panel2 is above Panel1, even though Panel1 is set first:
409409 Panel1.Align:=alTop;
410410 Panel1.Top:=1;
411411 Panel2.Align:=alTop;
412412 Panel2.Top:=0;
413413end;
414414```
415415
416416# 布局
417417
418418## 行,列和线
419419
420420你可以使用ChildSizing属性来对齐行和列中的子控件,例如:
421421
422422- ChildSizing.Layout=cclLeftToRightThenTopToBottom
423423- ChildSizing.ControlsPerLine=3
424424- AutoSize=false(组框不能重新调整大小来适应子控件)
425425
426426![](/wiki-images/1/10/Autosize_layout_lefttoright.png)
427427
428428**Layout(布局)**属性默认是cclNone。如果你设置**Layout**为另一个值,每一个有*正常*锚定的控件都将被对齐。*正常*锚定意味着:
429429
430430- Anchors=\[akLeft,akTop\]
431431- AnchorSide\[akLeft\].Control=nil
432432- AnchorSide\[akTop\].Control=nil
433433- Align=alNone
434434
435435值**cclLeftToRightThenTopToBottom**将在顶部,左侧放置第一个子项,在其右侧放置第二个子项,以此类推。这是一条**线**。属性**ControlsPerLine**定义何时开启一行新行。在上面的示例中,每一条线(行)有3个控件。这里有12个控件,所以这里有4条线(行),每 行有3个控件(列)。如果*ControlsPerLine*是0,意味着每行控件数量不受限制 - 这里将仅有带有全部子控件的一行。
436436
437437你可以看到这些行有不同的大小,每一行都有最大控件的大小,并且这些被重新调整大小到列宽。在行之间没有空格。在 图像中的空格来自使用的主题,而不是来自[[LCL]]。
438438
439439## 固定行和列之间的空间
440440
441441你可以在这些属性之间添加空格:
442442
443443- ChildSizing.VerticalSpacing - 行间距
444444- ChildSizing.HorizontalSpacing - 列间距
445445- ChildSizing.LeftRightSpacing - *所有*列的左右间距
446446- ChildSizing.TopBottomSpacing - *所有*列的上下间距
447447
448448上面的示例使用 ChildSizing.VerticalSpacing=6, ChildSizing.HorizontalSpacing=15, ChildSizing.LeftRightSpacing=30, ChildSizing.TopBottomSpacing=10, AutoSize=true
449449
450450![](/wiki-images/a/a9/Autosize_layout_parentspacing.png)
451451
452452另外,你可以使用BorderSpacing属性为每个控件设置单独的空间。
453453
454454## 放大
455455
456456上面的示例重新调整组框的大小到需要的空间。如果你的组框有一个固定的大小,或者如果它不能自由地重新调整大小, 例如,如果组框应该填充整个窗体的宽度,那么子控件应该放大。这里有一些模式。默认模式*ChildSizing.EnlargeHorizontal=crsAnchorAligning*是不能放大任何东西的。在右边的空间将不被使用。
457457
458458- crsAnchorAligning - 不使用额外的空间
459459- crsScaleChilds - 使用相同的因数成倍增加宽度/高度
460460- crsHomogeneousChildResize - 向每个宽度/高度添加相同的量
461461- crsHomogeneousSpaceResize - 在子控件之间每个空间中添加相同的量
462462
463463### crsScaleChilds(成倍增加)
464464
465465ChildSizing.EnlargeHorizontal=crsScaleChilds, ChildSizing.EnlargeVertical=crsScaleChilds, AutoSize=false
466466
467467![](/wiki-images/b/b0/Autosize_layout_scalechilds.png)
468468
469469例如,如果客户端宽度(ClientWidth)是所需宽度的两倍,那么每个子控件的宽度都将是所需宽度的两倍。
470470
471471### crsHomogeneousChildResize(单倍增加)
472472
473473ChildSizing.EnlargeHorizontal=crsHomogeneousChildResize, ChildSizing.EnlargeVertical=crsHomogeneousChildResize, AutoSize=false
474474
475475![](/wiki-images/3/39/Autosize_layout_homogeneouschildresize.png)
476476
477477例如,如果客户端宽度(ClientWidth)比所需要宽度大30像素,那么每个子控件都将宽10像素。
478478
479479### crsHomogeneousSpaceResize(定量增加)
480480
481481ChildSizing.EnlargeHorizontal=crsHomogeneousSpaceResize, ChildSizing.EnlargeVertical=crsHomogeneousSpaceResize, AutoSize=false
482482
483483![](/wiki-images/9/96/Autosize_layout_homogeneousspaceresize.png)
484484
485485例如,如果客户端宽度(ClientWidth)比所需要宽度大40 pixel,在左,右和每个子控件之间都将有10 pixel空间。
486486
487487## 收缩
488488
489489收缩工作类似于放大。如果没有足够的空间供控件使用,你可以设置不同的模式。**ShrinkHorizontal(水平收缩)**, **ShrinkVertical(垂直收缩)**。
490490
491491## 单个单元格(Individual cells)
492492
493493在上面的示例中,所有的控件都被同样地重新调整大小,每个控件都填充整个*单元格(cell)*。*单元格(cell)*是在具体的行和列中的空间。通常一个控件会填充整个单元格空间。可以使用属性**BorderSpacing.CellAlignHorizontal** 和**BorderSpacing.CellAlignVertical**更改。
494494
495495例如,设置Fifth按钮的*BorderSpacing.CellAlignHorizontal*为**caCenter**,你将得到这样:
496496
497497![](/wiki-images/d/d3/Autosize_layout_cellhorizontal_cacenter.png)
498498
499499CellAlignHorizontal/CellAlignVertical有四个可能的值:
500500
501501- caFill:子控件填充单元格的整个宽度(高度)
502502- caCenter:子控件在单元格中使用它的首选宽度(高度)并将居中
503503- caLeftTop:子控件在单元格中使用它的首选宽度(高度)并将左对齐
504504- caRightBottom:子控件在单元格中使用它的首选宽度(高度)并将右对齐
505505
506506![](/wiki-images/c/c0/Autosize_layout_cellalign.png)
507507
508508# 使用 OnResize / OnChangeBounds 自定义布局
509509
510510有时,[[LCL]]布局是不够用的。下面的示例显示一个GroupBox1带有一个ListBox1和一个Memo1。ListBox1应该填充1/3的空间,Memo1占 据剩余的空间。
511511
512512![](/wiki-images/4/4b/Autosize_onresize.png)
513513
514514无论何时重新调整GroupBox1大小,ListBox1.Width都应该是1/3。为达到这个目的,设置 GroupBox1的OnResize事件为:
515515
516516``` pascal
517517procedure TForm1.GroupBox1Resize(Sender: TObject);
518518begin
519519 ListBox1.Width := GroupBox1.ClientWidth div 3;
520520end;
521521```
522522
523523### 常见错误:OnResize事件错误
524524
525525不要将你*所有的*调整大小代码放入到窗体的OnResize事件中。窗体OnResize事件仅当窗 体被重新调整大小时被调用。子控件(例如,GroupBox1)将会稍后重新调整大小,因此GroupBox1.ClientWidth在FormResize事件期间仍然有旧值。你必需使用GroupBox1.OnResize事件来响应GroupBox1.ClientWidth的更改。
526526
527527### 常见错误:Width(宽度)代替ClientWidth(客户端宽度), AdjustClientRect(调整客户端矩形)
528528
529529Width(宽度)是包含框架在内的尺寸大小。ClientWidth是不包含框架的内部宽度。有一些框架(像 TPanel)会绘制一个附加的框架。那么你必需使用AdjustClientRect。相同的示例,但是在一个 Panel1中是一个ListBox1,而不是一个GroupBox1:
530530
531531``` pascal
532532procedure TForm1.Panel1Resize(Sender: TObject);
533533var
534534 r: TRect;
535535begin
536536 r := Panel1.ClientRect;
537537 Panel1.AdjustClientRect(r);
538538 ListBox1.Width := (r.Right - r.Left) div 3;
539539end;
540540```
541541
542542# 自定义控件
543543
544544当你写你自己的控件时,你可以重写(override)和微调[[LCL]]自动大小的很多部分。
545545
546546## SetBounds, ChangeBounds, DoSetBounds
547547
548548当属性 Left, Top, Width, Height, BoundsRect被设置时,或者用户直接调用时,**SetBounds**将被调用。 SetBounds更新BaseBounds和BaseParentClientSize,这就用于锚定以保持距离。例如,加载一个带有TMemo的窗 体,并且lfm包含TMemo的Left和Width,接下来TMemo将会调用两次SetBounds。当用户最 大化一个窗口时,SetBounds是被窗体调用的,而不是被TMemo调用的,以保持TMemo的 BaseBounds。如果TMemo被锚定到右侧,那么TMemo的宽度基于BaseBounds和 BaseParentClientSize更改。记住,给定的aLeft, aTop, aWidth, aHeight可能是无效的,并且在应用前通过[[LCL]]更改。Delphi更经常的调用SetBounds。SetBounds使用KeepBase=false调用ChangeBounds。
549549
550550每当通过属性或[[LCL]]的布局器设置控件的位置或大小时,都会调用**ChangeBounds**。SetBounds 使用KeepBase=false内部调用ChangeBounds , 而[[LCL]]布局器使用KeepBase=true来调用它。重新这些代码可能会更改首先大小或重新调整其它控件的大小。记住,给定的aLeft, aTop, aWidth, aHeight可能是无效的,并在应用前通过[[LCL]]更 改。你可以调用这个函数。
551551
552552**DoSetBounds**是一个低级函数,用以设置私有变量FLeft, FTop, FWidth, FHeight。不要调用这个函数,仅[[LCL]]调用它。它也相应地更新FClientWidth和FClientHeight。重写这个函数以更新控件的内容布局, 例如滚动条。一如往常:在这里不绘制,但会调用Invalidate并在OnPaint或重新绘制(override Paint)中绘制。
553553
554554**DoAdjustClientRectChange**通过[[LCL]]或[[LCL]]调用,当ClientRect更改时,宽度和高度保持不变。 **WMSize**是为实现Delphi/VCL的兼容性而存在的。通过[[LCL]] interface调用,并在每次边界更改时更改。
555555
556556## AdjustClientRect(调整客户端矩形)
557557
558558方法 AdjustClientRect 可以被你自定义的控件所重写(override),并且影响 Align, ChildSizing.Layout 和AnchorSides。它不影响Left, Top的意思,也不影响正常的锚定(例如设置)。
559559
560560当你想绘制你自己的框架时,那么子控件应该在这些框架中对齐。例如,TPanel绘制一个框架,并通过重写方法**AdjustClientRect**来减少客户端区域:
561561
562562``` pascal
563563 TCustomPanel = class(TCustomControl)
564564 ...
565565 protected
566566 ...
567567 procedure AdjustClientRect(var aRect: TRect); override;
568568 ...
569569
570570procedure TCustomPanel.AdjustClientRect(var aRect: TRect);
571571var
572572 BevelSize: Integer;
573573begin
574574 inherited AdjustClientRect(aRect);
575575
576576 BevelSize := BorderWidth;
577577 if (BevelOuter <> bvNone) then
578578 inc(BevelSize, BevelWidth);
579579 if (BevelInner <> bvNone) then
580580 inc(BevelSize, BevelWidth);
581581
582582 InflateRect(aRect, -BevelSize, -BevelSize);
583583end;
584584```
585585
586586### AdjustClientRect(调整客户端矩形)和Align(对齐)
587587
588588AdjustClientRect可以用于减少所有自动调整大小操作所使用的客户端区域。例如TPanel使用 AdjustClientRect来减少客户端区域的borderwidth(边界宽度):
589589
590590![](/wiki-images/c/ca/Adjustclientrect_align.png)
591591
592592在截图中的Button1是使用Align=alClient创建的。ChildSizing.Layout也会受到影响。
593593
594594当通过AnchorSides(锚定侧)锚定到一个父类对象时,AdjustClientRect也会被使用:
595595
596596``` pascal
597597 Button1.AnchorParallel(akTop,0,Button1.Parent);
598598```
599599
600600Button1的顶部被锚定到父类客户端区域的顶部。如果AdjustClientRect添加3到顶部,那么Button1.Top将会是3 (3加上0)。
601601
602602## Own AutoSize
603603
604604当*AutoSize*被设置为true时,控件应该被重新调整为首选的大小,如果有可能的话。
605605
606606### 首选大小
607607
608608新的大小经由[[LCL]]通过**GetPreferredSize''获取,它调用**CalculatePreferredSize**, 它可以被重写(overridden)。例如,让我们写一个**TQuadrat''', 它是一个TShape,但是它的高度应该等于它的宽度:
609609
610610``` pascal
611611 TQuadrat = class(TShape)
612612 protected
613613 procedure CalculatePreferredSize(var PreferredWidth,
614614 PreferredHeight: integer; WithThemeSpace: Boolean); override;
615615 end;
616616...
617617procedure TQuadrat.CalculatePreferredSize(var PreferredWidth,
618618 PreferredHeight: integer; WithThemeSpace: Boolean);
619619begin
620620 PreferredHeight:=Width;
621621end;
622622```
623623
624624方法CalculatePreferredSize获取两个变量参数:*PreferredWidth*和*PreferredHeight* 。它们默认为0,这意味着:这里没有首选大小,因此[[LCL]]将 不会更改大小。上面的函数设置*PreferredHeight*为当前的*Width*。布尔参数*WithThemeSpace*已经被弃用,并且始终是false。
625625
626626**重要**: CalculatePreferredSize禁止更改一个控件的边界或任意其它值,因为 这样做将会创建一个循环。
627627
628628计算*PreferredWidth(首选宽度)/Height(高度)*可能会代价很高。因此[[LCL]]会缓存结果,直到控件调用 *InvalidatePreferredSize* 。在我们的示例中,*PreferredHeight(首选高度)*依赖于*Width*,因此当*Width*更改时,我们必需使其无效:
629629
630630``` pascal
631631 TQuadrat = class(TShape)
632632 protected
633633 ...
634634 procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
635635 end;
636636...
637637procedure TQuadrat.DoSetBounds(ALeft, ATop, AWidth, AHeight: integer);
638638begin
639639 inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
640640 InvalidatePreferredSize;
641641 // Note: The AdjustSize can be omitted here, because the [[LCL]] does that after calling DoSetBounds.
642642end;
643643```
644644
645645当边界更改时,[[LCL]]将自动地触发自动调整大小,因此示例是完整。
646646
647647CalculatePreferredSize的默认T实施询问widget集,可能会返回 一个首选的宽度和/或高度。每一个控件都可以重写 (override)CalculatePreferredSize方法。例如,TImage将重写(override)它,并将返回图像的大小。如果没有可用的首选宽度(高度),返回值是0,[[LCL]]将保持当前是宽度(高度)。如果0是你的控件的有效大小,你必须设置ControlStyle标志 csAutoSize0x0 (ControlStyle:=ControlStyle+\[csAutoSize0x0\];)。[[LCL]] 控件面板是一个示例。
648648
649649### AdjustSize(调整大小)
650650
651651当首选大小依赖于一个新的属性时,那么每次属性更改时,自动大小都必须被触发。例如:
652652
653653``` pascal
654654procedure TQuadrat.SetSubTitle(const AValue: string);
655655begin
656656 if FSubTitle = AValue then exit;
657657 FSubTitle := AValue;
658658 InvalidatePreferredSize;
659659 AdjustSize;
660660end;
661661```
662662
663663# 使用禁用自动大小(DisableAutoSizing),启用自动大小(EnableAutoSizing)来减少资源管理开销(overhead)
664664
665665自从Lazarus 0.9.29 以来,lazarus有了一个新的自动调整大小的算法,它减少了资源管理开销并运行深度嵌套依赖关系。一直到Lazarus 0.9.28,DisableAlign/EnableAlign和Disable /EnableAutoSizing仅对一个控件和它的直系子控件有效。
666666
667667你每次更改一个属性时,[[LCL]]都会触发一次布局的重新计算:
668668
669669``` pascal
670670Label1.Caption := 'A'; // first recompute
671671Label2.Caption := 'B'; // second recompute
672672```
673673
674674重新计算将会触发事件和发生信息。为减少资源管理开销,你可以暂停(suspend)自动大小:
675675
676676``` pascal
677677DisableAutoSizing;
678678try
679679 Label1.Caption := 'A'; // no recompute
680680 Label2.Caption := 'B'; // no recompute
681681finally
682682 EnableAutoSizing; // one recompute
683683end;
684684```
685685
686686Y你必需平衡调用禁用/启用自动大小(Disable/EnableAutoSizing)。仅在一次相关的 (早期) 禁用自动大小(DisableAutoSizing)后调用启用自动大小(EnableAutoSizing) 时,才会启动启用自动大小(EnableAutoSizing)
687687
688688自0.9.29以来,禁用/启用自动大小Disable/EnableAutoSizing)适用于整个窗体。这意味着每一次调用DisableAutoSizing都会终止这个窗体上的**所有**控件自动调整大小。如果你编写你自己的控件,你现在可以使用下面的:
689689
690690``` pascal
691691procedure TMyRadioGroup.DoSomething;
692692begin
693693 DisableAutoSizing; // disables not only TMyRadioGroup, but the whole form's autosizing
694694 try
695695 // delete items ...
696696 // add, reorder items ...
697697 // change item captions ...
698698 finally
699699 EnableAutoSizing; // recompute
700700 end;
701701end;
702702```
703703
704704这基本上意味着:你不必在意。只需要调用Disable/EnableAutoSizing.
705705
706706注意:这是错误的:
707707
708708``` pascal
709709Button1.DisableAutoSizing;
710710Label1.EnableAutoSizing; // wrong: every control has its own autosizing reference counter
711711```
712712
713713## 禁用自动大小(DisableAutoSizing)和窗体边界
714714
715715例如在Linux系统中,在异步窗口管理器下,DisableAutoSizing有另外一个有用的效果。每次重新调整窗体大小或者移动边界都会发送非widget集(DoSendBoundsToInterface)。即使窗体未显示,处理程序也会重新调整大小。窗口管理器常常仅将这些边界作为建议处理。窗口管理器有它自己的逻辑,并且通常仅使用发送的第一步的边界。第二步、第三步或更进一步的移动将会被忽略。使用DisableAutoSizing,你可以确保将最终边界发送到widget集,从而使窗体边界更可靠。
716716
717717# 示例:一个按钮面板
718718
719719这个示例结合一些[[LCL]]布局机制来创建一个包含三个按钮的面板:一个*Help*按钮到左侧,*Ok*和*Cancel*按钮到右侧。我们希望面板在窗体的底部填充整个宽度。按钮和面板都会自动调整大小来适合使用的字体和主题。
720720
721721步骤 1: 创建面板并设置它的Align属性为alBottom。添加三个TBitBtns。
722722
723723![](/wiki-images/7/7e/Autosize_example_buttonpanel1.png)
724724
725725设置BitBtns的*Kind*属性来显示符号(glyphs)。你可能需要设置GlyphShowMode为gsmAlways来在你的平台上查看它们。设置BitBtn的*AutoSize*属性为*True*,这将收缩/放大按钮以完美地适合符号(glyphs)和文本。取决于你的主题和平台,你可能会注意到按钮有不同的高度。
726726
727727![](/wiki-images/4/49/Autosize_example_buttonpanel2.png)
728728
729729设置help按钮的*Align*属性为*alLeft*,并设置其它两个按钮的*Align*属性为*alRight* 。这将垂直放大按钮并将移动它们到最左侧/右侧。alLeft/alRight对宽度没有影响,因此按钮使用它们的首选宽度。
730730
731731![](/wiki-images/b/b6/Autosize_example_buttonpanel3.png)
732732
733733面板高度仍然是不变的。现在设置面板的*AutoSize*属性为*True*。面板现在垂直收缩来适合最高的按钮。
734734
735735![](/wiki-images/3/36/Autosize_example_buttonpanel4.png)
736736
737737*Ok*按钮有一个简短的标题(caption),因此按钮是非常短的。设置按钮的*Constraints.MinWidth*为75。按钮现在将稍微放大一些。
738738
739739![](/wiki-images/3/32/Autosize_example_buttonpanel5.png)
740740
741741现在在按钮的周围添加一些空格。设置面板的*ChildSizing.LeftTopSpacing/RightBottomSpacing/HorizontalSpacing*为*6*.
742742
743743![](/wiki-images/4/46/Autosize_example_buttonpanel6.png)
744744
745745最后清除面板的*标题(Caption)*,并设置它的*BevelOuter*为*bvNone*。
746746
747747![](/wiki-images/4/4e/Autosize_example_buttonpanel7.png)
748748
749749# 滚动(Scrolling)
750750
751751一些[[LCL]]控件(像*TScrollBox*, *TForm*,和*TFrame*)显示滚动条,如果其子控件太大,而无法适应滚动框,窗体或框架的话。它们从其祖先**TScrollingWinControl**继承这种行为。
752752
753753一个滚动控件的**逻辑客户区域(logical client area)**可以大于**可见客户区域(visible client area)**。*可见客户区域(visible client area)*是**ClientRect**它总是从0,0开始,并且它的宽度和高度是内部区域。例如,在一个TGroupBox中,在框架内部中大小。因此下面总是true:
754754
755755``` pascal
756756ClientWidth <= Width
757757ClientHeight <= Height
758758```
759759
760760**逻辑客户区域(logical client area)**是通过方法**GetLogicalClientRect**.定义的。默认情况下,它与*ClientRect*相同。当一个子控件锚定到右侧时,它使用*逻辑客户区域(logical client area)*。 *TScrollingWinControl* 重写这个方法并返回滚动条的*范围(Range)*,如果它们大于*ClientRect*的话。 **范围(Range)**可以使用*AutoScroll=true*来手动设置或自动设置。一个关于*AutoScroll=true*的示例:
761761
762762![](/wiki-images/d/db/Autoscroll_all_fit1.png)
763763
764764上面的按钮有一个固定是宽度200。下面的按钮被锚定到面板的右侧。因此,子控件有一个首先的宽度200。因为面 板是大于200的,逻辑客户区域(logical client area)也是更大的,因此下面的按钮扩展。
765765
766766现在面板是收缩的,因此ClientWidth变得小于200
767767
768768![](/wiki-images/2/27/Autoscroll_not_fit1.png)
769769
770770首先的宽度仍然是200,因此逻辑客户区域(logical client area)现在是200,并大于可见客户区域(visible client area)。下面的按钮现在有一个200的宽度,面板显示一个水平滚动条。
771771
772772## 滚动(Scroll)位置
773773
774774更改一个滚动条的位置并不会方法任何子控件的左侧或顶部,也不会更改逻辑客户区域(logical client area),也不会影响自动大小。子控件仅会模拟移动。
775775
776776## 滚动(Scrolling)和自动大小(AutoSize)
777777
778778当AutoSize=true时,[[LCL]]将扩展控件以容纳其所有的子控件,并且不需要滚动条。如果控件不能被扩展,那么(仅)执行 AutoSize的第二个动作:移动子控件。
779779
780780# 停靠(Docking)
781781
782782停靠(Docking)使用这页中描述的方法和属性,查看[[Docking|停靠]].
783783
784784# 分隔符
785785
786786查看[[TSplitter|分隔符]].
787787
788788# TLabel.WordWrap
789789
790790**TLabel.WordWrap**更改标签(label)的首选大小的行为。**WordWrap=true** 要求标签(label)的宽度是固定的,例如,通过锚定标签(label)的左、右侧的大小。标签(label)的 首选高度将通过打断标题(Caption)成多行的方式来重新计算。
791791
792792# DPI自动调整和绝对布局的自动调整
793793
794794在历史上,[[LCL]]主要用于设计绝对布局,尽管Lazarus为灵活布局提供大量的选项,像:对齐(Align),锚定(Anchors),等等,像在这篇文章的其它部分所 描述的那样。除此之外,在历史上,它忽略了目标的DPI,而使用像素值来测量控件的左侧(left),顶部(top),宽度(width)和高度(height)属性。对于桌面平台和Windows CE来说,这已经工作地相当不错了,但是随着[[LCL]]支持Android的到来,这已经不能被忽视。从Lazarus 0.9.31开始,[[LCL]]可以将[[LCL]]的绝对布局以像素的形式重新解释为一个灵活的网格。这里有多种模式可供 选择,并且它们将允许重新解释像素值来作为绝对值,或者作为DPI调整,或者只是作为窗体尺寸的一部分考虑。
795795
796796值得注意的是,这些新的规则仅影响没有对齐(Align)位置并且仅使用最标准锚定(Anchor)的控件.
797797
798798在这种情况下,这里的值仅针对DPI调整,这里有一个新的属 性:TCustomForm.DesignTimeDPI,这将存储被设计窗体系统的DPI值。当目标的DPI大于 设计时的DPI,定位的值将被扩大,否则将会被减少。桌面DPI的常见值是96,并且这是给定的默认值。
799799
800800属性DesignTimeDPI:整数读取FDesignTimeDPI然后写入FDesignTimeDPI;
801801
802802这种布局方法使用属性TApplication.LayoutAdjustmentPolicy进行控制调整
803803
804804``` pascal
805805 TLayoutAdjustmentPolicy = (
806806 lapDefault, // widget set dependent
807807 lapFixedLayout, // A fixed absolute layout in all platforms
808808 lapAutoAdjustWithoutHorizontalScrolling, // Smartphone platforms use this one,
809809 // the x axis is stretched to fill the screen and
810810 // the y is scaled to fit the DPI
811811 lapAutoAdjustForDPI // For desktops using High DPI, scale x and y to fit the DPI
812812 );
813813```
814814
815815并且,在下面的TControl的新方法允许强制进行一个特定控件和其所有子控件的一次布局自动调整,如何控制TControl特定衍生物,对此这样回应:
816816
817817``` pascal
818818TControl = class
819819public
820820...
821821 procedure AutoAdjustLayout(AMode: TLayoutAdjustmentPolicy;
822822 const AFromDPI, AToDPI, AOldFormWidth, ANewFormWidth: Integer); virtual;
823823 function ShouldAutoAdjustLeftAndTop: Boolean; virtual;
824824 function ShouldAutoAdjustWidthAndHeight: Boolean; virtual;
825825```
826826
827827例如,当屏幕旋转时,LCL-CustomDrawn-Android将调用AutoAdjustLayout 。
828828
829829# 更多细节
830830
831831很多控件重写(override) *TControl.DoAutoSize*执行实际地自动大小。
832832
833833重要: 很多Delphi控件重写(override)这个方法,很多控件在设置一些属性后会直接调用这个方法。
834834
835835在处理程序(handle)创建过程中,并非所有的接口都可以创建完整的设备上下文,这些上下文需要计算一些像文 本大小的事情。
836836
837837这就是为什么你应该总是调用*AdjustSize*而不是`DoAutoSize`的原因。
838838
839839`TControl.AdjustSize`以一种智能流行的方式调用`DoAutoSize`。
840840
841841在加载和处理程序(handle)创建过程中,会延迟调用。
842842
843843这种方法的最初的作用与*TWinControl.DoAutoSize*相同。但是,由于`DoAutoSize` 通常被衍生组件所重写,它并不是对执行所有的测试都有用,它会导致太多的资源开销。为减少这种情况,[[LCL]]调用`AdjustSize`来作为替换品。
844844
845845当设置AutoSize = true时,[[LCL]] 在宽度和高度上自动大小控件。这是[[LCL]]最复杂的一部分,因为最终的结果取决于近一百个属性。让我们简单地开始:
846846
847847[[LCL]]仅能自动调整*宽度(Width)* (高度(Height)),如果它可以自由重新调整大小的话。换句话说-宽度不会自动调整大小,如果:
848848
849849- 左侧和右侧是被锚定的。你可以使用**Anchors**属性锚定一侧,或者通过设置*Align*属性为alTop,alBottom或alClient。
850850- *宽度(Width)*被*Constraints(约束式)*属性所约束。约束式也可以通过widget集重写。例如,winapi并不允许重新调整一个组合框的高度。并且gtk widget集也不允许重新调整一个垂直滚动条的宽度。
851851
852852*高度(Height)*与*宽度(Width)*相同。
853853
854854新的大小是通过受保护(protected)的方法**TControl.CalculatePreferredSize**所计算得出来的。这个方法会要求widget集的一个适当的宽度和高度。例如,一个TButton有首先的宽度和高 度。一个TComboBox仅有一个首选的高度。首选宽度被作为0返回,因此[[LCL]]并不会自动大小宽度- 它保持宽度不变。一个TMemo没有首先的宽度或高度。因此,自动大小对一个TMemo没有影响。
855855
856856一些控件重写(override)这个方法。例如,TGraphicControlyan衍生物,像TLabel没有窗口处理程序,因此不能询问其widget。它们必需计算它们自己的首选宽度和高度。
857857
858858widget集必需为每个具有首选大小(宽度或高度或两者都有)的widget类重写(override)方法GetPreferredSize。
859859
860860## Parent.AutoSize(父类.自动大小)
861861
862862上面描述了简单的解释。真正的算法提供了很多的可能性因而变得更复杂。
863863
864864## Properties / Methods(属性/方法)
865865
866866- Left
867867- Top
868868
869869如果Parent\<\>nil,那么Left, Top是到父类客户端区域(非滚动的)的左侧像素,右侧像素的像素距离。记住客户端区域总是*不包含*父类的框 架和滚动条的。对于 Delphi用户来说:一些VCL控件,像TGroupbox,定义客户端区域为整个控件,包含框架,而另外一些控件则不是这样-[[LCL]]相比Delphi来说更加一致,因此其与Delphi不兼容。Left和Top可以是负数或者是大于客户端区域的数。一些widget集会定义一个最小值/最大值 ,在一些地方约有10.000或更多。
870870
871871当客户端区域是滚动的时,Left和Top将保持不变。
872872
873873在重新调整大小/移动期间,Left和Top并不总是与处理程序对的坐标同步。
874874
875875如果Parent=nil ,那么Left, Top取决于widget集和窗口管理器。直到Lazarus 0.9.25 ,这通常是窗体的客户端区域的left,top的屏幕坐标。这是与Delphi不兼容的。计划将其更改为窗口的Left, Top 。
876876
877877提示: 你每次更改Left和Top时,[[LCL]]会立即移动并重新计算整个布局。如果你想更改Left和Top,请改用:
878878
879879``` pascal
880880with Button1 do
881881 SetBounds(NewLeft, NewTop, Width, Height);
882882```
883883
884884- Width
885885- Height
886886
887887以像素形式的大小禁止为负数,并且大多数widget集不允许Width=0和/或Height=0 。在一些平台上的一些控件以Constraints.MinInterfaceWidth/Height的形式定义 一个较大的最小值约束。而不是重新大小一个控件为Width=0和/或Height=0 ,设置Visible=false或Parent=nil。在重新调整大小/移动期间,Width和Height并不总是与处理程序对的坐标同步。
888888
889889- BoundsRect
890890
891891等同于Bounds(Left, Top, Width, Height).
892892
893893新手常见错误:
894894
895895``` pascal
896896BoundsRect.Left := 3; // WRONG: common newbie mistake
897897```
898898
899899这没有效果, 因为读取BoundsRect的是一个函数。它在堆上创建一个临时的TRect 。上述等同于:
900900
901901``` pascal
902902var
903903 r: TRect;
904904begin
905905 r := BoundsRect; // fetch the bounds
906906 r.Left := 3; // change a value on the stack
907907end; // no change
908908```
909909
910910- ClientRect
911911
912912Left和Top总是0,0 。宽度和高度是客户端区域的可见像素大小。记住客户端区域不包含框架和滚动条。在一个可滚动的客户端区域中,逻辑客户端区域可能大于可见的客户端区域。
913913
914914- ClientOrigin
915915
916916返回客户端区域的左侧,顶部坐标0,0的屏幕坐标。注意,这个值是存储在接口(interface)中的位置。并不总是与[[LCL]]同步。当移动一个控件时,[[LCL]]设置边界到所需位置,并发送一条移动信息到接口(interface)。这取决于接口(interface)立即处理移动或排队处理移动。
917917
918918- LCLIntf.GetClientBounds
919919
920920返回一个控件的客户端边界。像ClientRect,但是Left和Top是到控件左侧,顶部的像素距离。例如在 一个TGroupBox上,Left, Top是左侧和右侧框架边界的宽度和高度。滚动在GetClientBounds上没有影响。
921921
922922- LCLIntf.GetWindowRect
923923
924924在调用后,ARect将是屏幕坐标中控件区域。这意味着,Left和Top将是处理程序对象的左侧和顶部像素的屏 幕坐标,Right和Bottom将是右侧和底部像素的屏幕坐标。
925925
926926- FBaseBoundsLock: integer
927927
928928通过LockBaseBounds/UnlockBaseBounds来增加/减小。在SetBounds调用期 间,用于保持FBaseBounds。
929929
930930- FBaseParentClientSize: TPoint
931931
932932Parent.ClientRect大小对FBaseBounds有效。FBaseBounds和 FBaseParentClientSize通常用于计算akRight (akBottom)的距离。当重新调整父类大小时,[[LCL]]知 道要保持什么距离。
933933
934934- FBoundsRectForNewParent: TRect
935935
936936当更改一个控件的父类时,会重新创建处理重新并可能会发送很多事情。尤其是停靠窗体过程是太不可靠了。因此将会保 存BoundsRect。VCL使用一种类似的机制。
937937
938938- fLastAlignedBounds: TRect
939939
940940查看TControl.SetAlignedBounds说明解释。简而言之:它停止在接口(interface)和[[LCL]]自动大小之间的一些循环。
941941
942942- FLastChangebounds: TRect
943943
944944用于停止调用具有相同坐标的ChangeBounds。这种情况经常发生。
945945
946946- FLastDoChangeBounds: TRect
947947
948948用于避免调用具有相同坐标的OnChangeBounds。这将减少用户定义的自动大小。
949949
950950- FLastResizeClientHeight: integer
951951- FLastResizeClientWidth: integer
952952- FLastResizeHeight: integer
953953- FLastResizeWidth: integer
954954
955955用于避免调用具有相同坐标的OnResize。这将减少用户定义的自动大小。
956956
957957- FLoadedClientSize: TPoint
958958
959959在加载期间,很多东西被迟延,很多东西被设置。并且最糟糕的是:以一种错误的顺序。这就是为什么在再次加载时,存 储和设置SetClientWidth/SetClientHeight调用的原因。使用这种方法,[[LCL]]可以恢复设计期间使用的距离(例如,akRight)。
960960
961961- FReadBounds: TRect
962962
963963类似于FLoadedClientSize,但是适用于 SetLeft,SetTop,SetWidth,SetHeight。
964964
965965- procedure SetBoundsRectForNewParent(const AValue: TRect);
966966
967967用于设置FBoundsRectForNewParent。查看上文。
968968
969969- procedure SetAlignedBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
970970
971971像SetBounds,但是不更改默认大小。
972972
973973- procedure SetInitialBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
974974
975975一个SetBounds的智能版本, r在创建和加载过程中减少资源开销(overhead)。
976976
977977- procedure UpdateBaseBounds(StoreBounds, StoreParentClientSize, UseLoadedValues: boolean); virtual;
978978
979979提交当前的边界为基础边界。
980980
981981- procedure SetClientHeight(Value: Integer);
982982- procedure SetClientSize(Value: TPoint);
983983- procedure SetClientWidth(Value: Integer);
984984
985985也是用于Delphi兼容。重新调整控件的大小,来获取想要的ClientRect大小。
986986
987987- procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
988988
989989这是内部的SetBounds。应用于约束式,更新基础边界,调用OnChangeBound, OnResize,锁定边界。
990990
991991- procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
992992
993993这个实际上设置FLeft, FTop, FWidth, FHeight私有(private)变量。
994994
995995- procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
996996
997997这是很多Delphi控件的标准的过程(procedure)重写(overriden)方法。 TWinControl也会重写它。
998998
999999- - 当边界被锁定时忽略调用
10001000 - 锁定FBoundsRealized来避免在自动调整大小期间的资源开销。
10011001
10021002ChangeBounds未锁定这种方法。
10031003
10041004- Function GetClientOrigin: TPoint; virtual;
10051005
10061006客户端区域的Left, Top的屏幕左侧。
10071007
10081008- Function GetClientRect: TRect; virtual;
10091009
10101010客户端区域的大小。(总是Left=0, Top=0)。
10111011
10121012- Function GetScrolledClientRect: TRect; virtual;
10131013
10141014在ClientRect中的可见客户端区域。
10151015
10161016- function GetChildsRect(Scrolled: boolean): TRect; virtual;
10171017
10181018返回相对于控件的左侧,顶部的客户端矩形。如果Scrolled是true,矩形将通过当前滚动值移动(查看示例 TScrollingWincontrol)。
10191019
10201020- function GetClientScrollOffset: TPoint; virtual;
10211021
10221022返回客户端区域的滚动偏移量。
10231023
10241024- function GetControlOrigin: TPoint; virtual;
10251025
10261026返回控件区域的左侧,顶部坐标0,0的屏幕坐标。(在屏幕上的控件的左侧,顶部像素)。注意,这个值是存储在接口 (interface)中的位置。并不总是与[[LCL]]同步。当移动一个控件时,[[LCL]]设置边界到所需位置,并发送一条移动信息到接口(interface)。这屈居于接口(interface)立即处理移动或排队处理移动。
10271027
10281028# 常见问题解答
10291029
10301030## 为什么自动大小(AutoSize)在设计器中不能正确的工作?
10311031
10321032在设计器中,控件可以被拖来拖去,属性几乎可以按照任何顺序设置。为了接受自动大小这一点,并避免可能的冲突,在 设计时,自动大小并不会在每次更改时都会更新。
10331033
10341034## 在一些东西更改时,为什么TForm.AutoSize不工作?
10351035
10361036查看[[Autosize / Layout|自动大小和窗体]]
10371037
10381038## 当创建很多控件时,我需要调用Application.ProcessMessages吗?
10391039
10401040在每一条信息后(例如,在每一次OnClick事件后),Application.ProcessMessages将被[[LCL]]自动调用。如果更改需要立即变得可看见的话,你需要自己调用它。例如:
10411041
10421042``` pascal
10431043procedure TFrom.Button1Click(Sender: TObject);
10441044begin
10451045 // change width of a control
10461046 Button1.Width := Button1.Width + 10;
10471047 // apply any needed changes and repaint the button
10481048 Application.ProcessMessages;
10491049 // do a lot of things that takes a long time
10501050 ...
10511051 // after leaving the OnClick the LCL automatically processes messages
10521052end;
10531053```
10541054
10551055## 在启用锚定的情况下,在运行时,控件重新调整大小,而不是使用当前值。为什么?
10561056
10571057akBottom意味着:与父类底部侧保持一定的距离。保持距离是通过基本边界定义。它们在设计时设置,或者在运 行时调用SetBounds或UpdateBaseBounds。
10581058
10591059例如: 一个TListBox (Anchors=\[akLeft,aTop\])在设计时有一个100像素的底部距离。并且通过一个按钮来启用/禁用TListBox的akBottom。现在启动应用程序并按下按钮来启用akBottom,将激活100像素的距离,因为这是程序员最 后定义的TListBox的基本边界。所有其它的重新调整大小动作都将会由[[LCL]]完成。无关紧要的大小,程序员会基于边界规则。你可以重新调整窗体的大小,并保持100像素的距离。为了将当前边界作为基本边界使用:
10601060
10611061``` pascal
10621062ListBox1.UpdateBaseBounds(true, true, false);
10631063ListBox1.Anchors := ListBox1.Anchors + [akBottom];
10641064```
10651065
10661066设置锚不会自动调用UpdateBaseBounds,因为这将会破坏独立更改属性的能力。
10671067
10681068## 在窗体中重新调整字符串网格列大小的OnResize事件中不工作
10691069
10701070当窗体的宽度( Width),高度(Height),客户端宽度(ClientWidth)或客户端高度(ClientHeight) 更改时,窗体的OnResize将会被触发。这本质上不依赖于TStringGrid。当然,它经常在调整窗体和 TStringGrid时发生。这意味着使用窗体的OnResize将经常会工作,但并不是总是这样。一个明显会失 败的示例,当主题更改时,在你的一个TForm中的一个TGroupBox中有一个TStringGrid。当主题 更改时,窗体大小保持不变,因此将不会触发Forms的OnResize。但是TGroupBox已更改,因此 TStringGrid也会重新调整大小。
10711071
10721072解决方案:使用TStringGrid的OnResize。
10731073
10741074## 为什么TForm.Width等同于TForm.ClientWidth?
10751075
10761076Mattias的注释:
10771077
10781078"这里有历史原因和技术原因。
10791079
10801080对于没有父类的窗体,Clientwidth等于宽度,因为真实的宽度包含框架在10年前的Linux上是不可用 的(至少在各种窗口管理器上是不可靠的)。我没有测试过,但是我听说现在使用gtk2是有这种可能的。主要问题是自 动大小,因为在窗体映射到屏幕前需要框架的大小。它可能仅在一个事件后才可用,这意味着你必须等待它,这对 ShowModal来说就意味着麻烦。但是,更改这项变化会破坏到很多使用现有[[LCL]]代 码的兼容,为此,我们需要在lfm文件中添加LCLVersion。
10811081
10821082在Lazarus trunk 1.7 中有一个新的编译器定义**LCLRealFormBounds**,它启用一个窗体的真实大小。为使用它,只需要使用LCLRealFormBounds ON来编译你的应用程序。到目前为止,仅支持win32的widget集。
10831083
10841084对于所有其它的控件来说,规则是ClientWidth\<=Width。Width是 ClientWidth加上widget框架值。问题是滚动条是否属于框架。我会说是,在不久前,它已经这样实施了。显然,这已经更改了。查看关于synedit的当前光标问题。"
10851085
10861086## 我得到一个无效循环/如何调试自动调整大小?
10871087
10881088这里有一些笔记,其它用户做错了什么,和如何发现:
10891089
10901090### 与Delphi的不同
10911091
10921092对于Delphi用户:请阅读:[[Autosize / Layout|Lazarus_vs_Delphi]]
10931093
10941094### 重写(Overriding)一个[[LCL]]方法,并触发一次重新计算
10951095
10961096你重写(override)一个方法,并告诉[[LCL]]来重新计算,即使什么都没有更改。检查AdjustSize,Realign,AlignControls, InvalidatePreferredSize。例如:
10971097
10981098``` pascal
10991099procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
11001100begin
11011101 // This will create an endless loop
11021102 InvalidatePreferredSize;
11031103
11041104 // This will create an endless loop too:
11051105 OtherComponent.Left:=10;
11061106 OtherComponent.Left:=20;
11071107
11081108 inherited SetBounds(ALeft, ATop, AWidth, AHeight);
11091109end;
11101110```
11111111
11121112说明:SetBounds方法经常被调用,即使没有任何更改。例如,一个"Left:=30;"也将执行此操作。
11131113
11141114改进措施:检查更改:
11151115
11161116``` pascal
11171117procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
11181118begin
11191119 if (Left <> ALeft) or (Top <> ATop) or (Width <> AWidth) or (Height <> AHeight) then
11201120 InvalidatePreferredSize;
11211121 inherited SetBounds(ALeft, ATop, AWidth, AHeight);
11221122end;
11231123```
11241124
11251125#### TWinControl.AlignControls
11261126
11271127``` pascal
11281128procedure AlignControls(aControl: TControl; var aRect: TRect); override;
11291129```
11301130
11311131AlignControls移动并改变所有子控件的大小。[[LCL]]使用Align=alCustom来实施(implementation) 忽略控件。
11321132
11331133参数aControl: TControl为保持与VCL的兼容性。[[LCL]]总是传递(passes) nil 。当应用Align属性时,TControl将给予aControl优先级。例如,当你有两个使用Align=alLeft的控件A,B时,那么在较下侧的左侧控件将被放到最左侧 。如果两者都有相同的左侧位置,那么按照创建顺序。现在假设你想在设计器中切换两个控件A,B。你拖拽B到左侧。这将导致B.Left设置为0。现在 AlignControls启动并找到A.Left=0和B.Left=0。通常情况下,A将获胜。为让B获胜,VCL调用AlignControls(B,r)。因此aControl是最后被移动的。与VCL截然不同,[[LCL]] 保持跟踪在TWinControl.fAlignControls中最后移动的控件,并应用在 TWinControl.CreateControlAlignList中的顺序。aControl参数始终是nil 。
11341134
11351135查看TWinControl.CreateControlAlignList。
11361136
11371137### OnResize/OnChangeBounds与[[LCL]]属性冲突
11381138
11391139你设置边界咬入(bite)[[LCL]]属性。例如,TLabel.AutoSize默认是true。如果你在 一个OnResiz事件中设置Label1.Width,[[LCL]]将 重新计算,调整Label1大小,并再次调用OnResize。在调试器中启动你的应用程序,使再次发生错误。当它进入循环时,如果你看到你的一个事件或你的方法在那里开始搜索,暂停应用程序并查看调用堆栈。例如:
11401140
11411141``` pascal
11421142procedure TMainForm.FormResize(Sender: TObject);
11431143begin
11441144 // if Button1 is anchored or AutoSize=true then the following might create an endless loop:
11451145 Button1.Width:=100;
11461146end;
11471147```
11481148
11491149### [[LCL]]接口(interface)错误,自定义widget
11501150
11511151有时,[[LCL]]接口(interface)或你的自定义控件有一个错误和取消[[LCL]] 边界。使用参数-dVerboseIntfSizing编译[[LCL]] 。这将写入[[LCL]]和[[LCL]]接口(interface)之间的通讯。如果一个widget不运行自由重新调整大小,它必须通过约束条件来告诉[[LCL]] 。在各种[[LCL]]接口(interface)和TWSControlClass.ConstraintWidth/Height 中搜索SetInterfaceConstraints。
11521152
11531153### alCustom
11541154
11551155你使用alCustom 。在早期的Lazarus版本中这只是实现了一半,但是一些聪明的程序员使用它来创建一些特殊的效果。现在它已经实现了,并且你的程序将不在工作。请查看 alCustom做什么: [[Autosize / Layout|alCustom]].
11561156
11571157# 参考
11581158
11591159- [[Docking|停靠]]
11601160- [[Anchor Sides|锚定侧]]
11611161
11621162# 贡献者和更改
11631163
11641164- 简体中文版本由 robsean 于 2020-02-18 创建(2021-03-10完成全部翻译)。
11651165
11661166---
11671167*From the Free Pascal wiki, page "Autosize / Layout/zh CN", as it stood on 2021-03-10 after a change by Robsean, 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