Difference between revisions of "Autosize / Layout/ru"

From Free Pascal wiki
Jump to navigationJump to search
 
(172 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Autosize / Layout}}
 
{{Autosize / Layout}}
 
 
----
 
<span style="color:#FF0000">ENG: '''AT THE MOMENT THIS PAGE IS UNDER TRANSLATION.''' <br /> RUS: '''В НАСТОЯЩИЙ МОМЕНТ СТРАНИЦА НАХОДИТСЯ В ПРОЦЕССЕ ПЕРЕВОДА.'''</span>
 
----
 
  
  
Line 11: Line 6:
 
LCL может автоматически изменять размер и положение элемента управления, поэтому он адаптируется к изменениям шрифта, темы и текста или другого содержимого. Если вы хотите запустить программу на нескольких платформах, или если ваши подписи доступны на нескольких языках, то ваши средства управления должны правильно адаптироваться к своей среде. LCL позволяет не только сделать быстрый начальный дизайн (перемещение элементов управления на форму с помощью мыши), но и позже установить несколько ключевых свойств, которые сделают регуляторы автоматически адаптироваться впоследствии измененным содержанием и т.д.  
 
LCL может автоматически изменять размер и положение элемента управления, поэтому он адаптируется к изменениям шрифта, темы и текста или другого содержимого. Если вы хотите запустить программу на нескольких платформах, или если ваши подписи доступны на нескольких языках, то ваши средства управления должны правильно адаптироваться к своей среде. LCL позволяет не только сделать быстрый начальный дизайн (перемещение элементов управления на форму с помощью мыши), но и позже установить несколько ключевых свойств, которые сделают регуляторы автоматически адаптироваться впоследствии измененным содержанием и т.д.  
  
*[[#Фиксированный дизайн|Фиксированный дизайн (Fixed design)]]: это значение по умолчанию при размещении элемента управления в дизайнере форм. Положение элемента управления фиксируется относительно его родителя. Размер и положение элемента управления (Left, Top) полностью изменяются программистом. Вы можете перемещатьэлемент с помощью мыши, и изменять его размер свободно.  
+
*[[#Фиксированный дизайн|Фиксированный дизайн (Fixed design)]]: это значение по умолчанию при размещении элемента управления в дизайнере форм. Положение элемента управления фиксируется относительно его родителя. Размер и положение элемента управления (Left, Top) полностью изменяются программистом. Вы можете перемещать элемент с помощью мыши и изменять его размер свободно.  
*[[#Align|Выравнивание (Aligned)]]: выравненные элементы управления заполняют оставшееся пространство родителя вверху, снизу, слева или справа, или заполняют всё оставшееся пространство.
+
*[[Autosize_/_Layout/ru#Выравнивание (Aligned)|Выравнивание (Aligned)]]: выравненные элементы управления заполняют оставшееся пространство родителя вверху, снизу, слева или справа, или заполняют всё оставшееся пространство.
*[[#Anchor_Sides|Закрепленные (Anchored)]]: вы можете закрепить стороны элемента управления (слева, сверху, справа, снизу) с его родителем или с другим элементот управления. Закрепление: LCL попытается оставаться на таком же расстоянии от точки привязки.
+
*[[Autosize_/_Layout/ru#Привязка сторон (Anchored)|Привязка (Anchored)]]: вы можете закрепить стороны элемента управления (слева, сверху, справа, снизу) с его родителем или с другим элементот управления. Закрепление: LCL попытается оставаться на таком же расстоянии от точки привязки.
*[[#Layout|Размещение (Layout)]]: элементы управления могут быть автоматически выровнены по строкам и столбцам (например, TRadioGroup)
+
*[[Autosize_/_Layout/ru#Разметка (Layout)|Разметка (Layout)]]: элементы управления могут быть автоматически выровнены по строкам и столбцам (например, TRadioGroup)
*[[#Custom_layout_with_OnResize_.2F_OnChangeBounds|Пользовательское через OnResize]]: можно выровнять элементы управления самостоятельно в коде, используя события OnResize и OnChangeBounds.
+
*[[Autosize_/_Layout/ru#Пользовательская разметка через OnResize/OnChangeBounds|Пользовательская разметка через OnResize/OnChangeBounds]]: можно выровнять элементы управления самостоятельно в коде, используя события OnResize и OnChangeBounds.
*[[#Custom_Controls|Пользовательские элементы управления]]: написав собственные элементы управления, вы можете переопределить почти каждое поведение LCL как вы хотите.
+
*[[Autosize_/_Layout/ru#Пользовательские элементы управления|Пользовательские элементы управления]]: написав собственные элементы управления, вы можете переопределить почти каждое поведение LCL как вы хотите.
  
 
==Правила приоритета==
 
==Правила приоритета==
Line 22: Line 17:
 
# Constraints (Ограничения)
 
# Constraints (Ограничения)
 
# Align (Выравнивание)  
 
# Align (Выравнивание)  
# Anchors(Якоря)
+
# Anchors(Привязки)
# ChildSizing.Layout
+
# ChildSizing.Layout  
# AutoSize
+
# AutoSize (Автомасштаб элемента)
# OnResize, OnChangeBounds - однако, если вы установите границы, которые конфликтуют с вышеуказанными правилами, то это создаст бесконечный цикл
+
# События OnResize, OnChangeBounds - однако, если вы установите границы, которые конфликтуют с вышеуказанными правилами, то это создаст бесконечный цикл
  
 
==Общие свойства==
 
==Общие свойства==
  
Несколько важных свойств могут быть изменены, чтобы настроить автоматическое изменение размера:
+
Чтобы настроить автоматическое изменение размера, можно изменить несколько основных свойств :
  
 
*Left, Top, Width, Height
 
*Left, Top, Width, Height
*[[#Авторазмер|AutoSize]]: авторазмер, указывает LCL автоматически изменить ширину и высоту элемента управления
+
*[[#Автомасштаб|AutoSize]]: Автомасштаб, указывает LCL автоматически изменить ширину и высоту элемента управления
*[[#Anchor_Sides|Anchors]]: позволяет создавать зависимости, например, чтобы заякорить ComboBox к правой стороне #Label.
+
*[[Autosize_/_Layout/ru#Привязка сторон (Anchored)|Anchors]]: позволяет создавать зависимости, например, чтобы привязать ComboBox к правой стороне #Label.
 
*[[#Align|Align]]
 
*[[#Align|Align]]
 
*Constraints: позволяет установить минимум и максимум для ширины и высоты
 
*Constraints: позволяет установить минимум и максимум для ширины и высоты
*[[#BorderSpacing|BorderSpacing]]: позволяет установить расстояние между заякоренными элементами управления
+
*[[Autosize_/_Layout/ru#Зазор|BorderSpacing]]: позволяет установить расстояние между привязанными элементами управления
*[[#Layout|ChildSizing]]: позволяет установить расположение и расстояние дочерних элементов управления
+
*[[Autosize_/_Layout/ru#Планировка (Layout)|ChildSizing]]: позволяет установить расположение и расстояние дочерних элементов управления
  
 
Внутренние алгоритмы объясняются здесь: [[LCL AutoSizing]].
 
Внутренние алгоритмы объясняются здесь: [[LCL AutoSizing]].
Line 43: Line 38:
 
=Фиксированный дизайн=
 
=Фиксированный дизайн=
  
Фиксированный ​​дизайн установлен по умолчанию. Якорь установлен на [akLeft, akTop], что означает, значения Top и Left не будут изменяться LCL. Если AutoSize равно False, LCL не изменяет ширину или высоту. Если AutoSize равно True, то ширина и высота изменяются по размеру содержимого. Например, TLabel.AutoSize умолчанию True и тем самым изменяя его текст будет изменяться размер TLabel, чтобы поместился измененный текст. TButton.AutoSize умолчанию установлен в False, такbv образом изменение надписи на кнопке не изменит размеры кнопки. При установке Button.AutoSize в True, кнопка будет уменьшаться или увеличиваться каждый раз при изменении Caption на кнопке или при изменении шрифта или темы. Обратите внимание, что это изменение не всегда происходит сразу. Например во время FormCreate всё автоизмение размера приостанавливается.
+
Фиксированный ​​дизайн установлен по умолчанию. Якорь установлен в значение <code>[akLeft, akTop]</code>, что означает, значения Top и Left не будут изменяться LCL. Если значение <code>AutoSize</code> равно False, LCL не изменяет ширину или высоту. Если значение  <code>AutoSize</code> равно True, то ширина и высота изменяются по размеру содержимого. Например, <code>TLabel.AutoSize</code> умолчанию True, поэтому при изменении текста в нем будет соответственно изменяться размер и <code>TLabel</code>, чтобы измененный текст поместился в контроле полностью. <code>TButton.AutoSize</code> умолчанию установлен в False, таким образом изменение надписи на кнопке не изменит размеры кнопки. При установке значения <code>Button.AutoSize</code> в True, кнопка будет уменьшаться или увеличиваться каждый раз при изменении <code>Caption</code> на кнопке или при изменении шрифта или темы. Обратите внимание, что это изменение не всегда происходит сразу. Например во время FormCreate всё автоизмение размера приостанавливается.
В любой момент вы можете изменить свойства Left, Top, Width и Height.
+
В любой момент вы можете изменить свойства <code>Left</code>, <code>Top</code>, <code>Width</code> и <code>Height</code>.
  
=Авторазмер=
+
=Автомасштаб=
  
<var>AutoSize</var> логическое свойство во многих классах; оно позволяет отрегулировать размер элемента управления автоматически учитывать изменения в тексте или графике, содержащейся в нем, и позволяет наиболее эффективно использовать имеющееся пространство. Это очень важный механизм для создания кроссплатформенных форм.
+
<code>AutoSize</code>(автомасштаб) - логическое свойство во многих классах; оно позволяет отрегулировать размер элемента управления автоматически, учитывать изменения в тексте или графике, содержащейся в нем, и позволяет наиболее эффективно использовать имеющееся пространство. Это очень важный механизм для создания кроссплатформенных форм.
  
Обычно AutoSize = True делает две вещи для видимого элемента управления:
+
Обычно <code>AutoSize</code> равенTrue и делает две вещи для видимого элемента управления:
* Если возможно, изменяет управление в нужный размер. Например ширина и высота TButton изменяется в соответствии с надписью, в то время как TEdit изменяется только в высоту. Ширина TEdit не изменяется автоматически. Вы можете изменить ширину TEdit. (см GetPreferredSize).
+
* Если возможно, изменяет управление в нужный размер. Например ширина и высота <code>TButton</code> изменяется в соответствии с надписью, в то время как <code>TEdit</code> изменяется только в высоту. Ширина <code>TEdit</code> не изменяется автоматически. Вы можете изменить ширину <code>TEdit</code> самостоятельно.(см GetPreferredSize).
* Она передвигает все фиксированно расположенные дочерние элементы управления, так чтобы самый левый дочерний элемент управления имел Left = 0 (зависит от BorderSpacing) и самый верхний дочерний элемент управления имел Top = 0.
+
* Оно передвигает все фиксированно расположенные дочерние элементы управления так, чтобы самый левый дочерний элемент управления имел Left = 0 (зависит от значения свойства <code>BorderSpacing</code>) и самый верхний дочерний элемент управления имел Top = 0.
  
 
==Отличия от Delphi==
 
==Отличия от Delphi==
  
* AutoSize в Delphi происходит только тогда, когда определенные свойства изменяются, например, когда шрифт из TLabel изменяется.LCL AutoSize всегда активен. Delphi позволяет изменить размер TLabel, который имеет AutoSize = True, LCL нет.
+
* <code>AutoSize</code> в Delphi происходит только тогда, когда определенные свойства изменяются, например, когда шрифт из <code>TLabel</code> изменяется. В LCL <code>AutoSize</code> всегда активен. Delphi позволяет изменить размер <code>TLabel</code>, который имеет AutoSize = True, LCL - нет.
 
* Скрытые управления не изменяют размер автоматически.
 
* Скрытые управления не изменяют размер автоматически.
* Изменение размера элемента управления не изменяет размер/расположение заякоренных дочерних элементов управления во время загрузки. Имейте в виду, что конструкторы элементов управления можно вызвать во время загрузки. При использовании akRight, akBottom якоря с установленными AnchorSides и BorderSpacing сохраняют правильное расстояние.
+
* Изменение размера элемента управления не изменяет размер/расположение заякоренных(привязанных) дочерних элементов управления во время загрузки. Имейте в виду, что конструкторы элементов управления можно вызвать во время загрузки. При использовании <code>akRight</code>, <code>akBottom</code> якоря с установленными <code>AnchorSides</code> и <code>BorderSpacing</code> сохраняют правильное расстояние.
  
==Авторазмер и изменение размера элемента управления==
+
==Автомасштаб и изменение размера элемента управления==
  
AutoSize=false, кнопки приведены по-умолчанию в фиксированный размер.
+
С помощью свойства кнопки <code>AutoSize=false</code> задаются фиксированный размер по умолчанию.
  
 
[[Image:Autosize1.png]]
 
[[Image:Autosize1.png]]
  
При установке AutoSize = True для каждой кнопки, кнопки увеличиваются (или уменьшаются) в соответствии с текстом и темой.
+
При установке <code>AutoSize=true</code> для каждой кнопки, кнопки растягиваются (или сжимаются) в соответствии с текстом и темой.
  
 
[[Image:Autosize on.png]]
 
[[Image:Autosize on.png]]
  
Авторазмер не уменьшает до минимально возможного размера, как вы можете видеть кнопку ОК. Он использует метод GetPreferredSize элемента управления, который вызывает метод CalculatePreferredSize. Реализация по умолчанию TWinControl запрашивает widgetset, которая могла бы иметь предпочтительную ширину или высоту. Каждый элемент управления может переопределить метод CalculatePreferredSize. Например TImage отменяет его и возвращает размер изображения. Если предпочитаемая ширина (высота) не доступна, возвращаемым значением является 0, и LCL будет сохранять ширину (высоту) (если не установлен ControlStyle флаг csAutoSize0x0, который в настоящее время используется только TPanel).
+
<code>AutoSize</code> не сжимает элемент управления до минимально возможного размера, как вы можете видеть по кнопке OK. Он использует метод <code>GetPreferredSize</code> элемента управления, который вызывает метод <code>CalculatePreferredSize</code>. По умолчанию реализация <code>TWinControl</code> запрашивает виджетсет, который может иметь оптимальную ширину или высоту. Каждый элемент управления может переопределять метод <code>CalculatePreferredSize</code>. Например, <code>TImage</code> переопределяет его и возвращает размер изображения. Если нет оптимальной ширины (высоты), возвращаемое значение равно 0, и [[LCL]] будет хранить ширину(высоту) элемента управления (если не установлен флаг <code>ControlStyle = csAutoSize</code>, который в настоящее время используется только <code>TPanel</code>).
  
TWinControl вычисляет размер всех его дочерних элементов управления и использует его для вычисления его предпочтительного размера.
+
<code>TWinControl</code> вычисляет размер всех своих дочерних элементов управления и использует это для вычисления своего оптимального размера.
  
Когда элемент управления привязан к левой и правой, его ''ширина фиксируется''. Например, с ''Align = alTop'' элемент привязан к левой и правой и имеет ширину родителя. Если '' Parent.AutoSize '' истинно, то '' Parent '' будет использовать предпочтительную ширину элемента управления, чтобы вычислить свою предпочтительную ширину, и, таким образом, контроль будет изменен, чтобы его предпочтительной шириной. Смотреть [[Autosize_/_Layout#Align_and_AutoSize|Align and AutoSize]]. Если предпочитаемый ширина не доступен, то последние черту со используются ('''BaseBounds''' или '''ReadBounds'''). Если не устанавливались границы, используется метод ''GetControlClassDefaultSize''. То же самое для '''высоты''' и крепления к верхней и нижней.
+
Когда элемент управления привязан как  слева, так и справа, его ''ширина фиксирована''. Например, со значением привязки <code>Align=alTop</code> элемент управления привязан слева и справа, и соответствует ширине Родителя. Если <code>Parent.AutoSize</code> имеет значение true, тогда ''Родитель'' будет использовать оптимальную ширину элемента управления для вычисления своей собственной оптимальной ширины, и, таким образом, размер элемента управления будет изменен до его оптимальной ширины. См. [[Autosize_/_Layout/ru#Выравнивание и свойство AutoSize|Выравнивание и свойство AutoSize]]. Если значение оптимальной ширины недоступно, используются последние установленные границы ('''BaseBounds''' или '''ReadBounds'''). Если никаких ограничений не было установлено, используется метод <code>GetControlClassDefaultSize</code>. То же самое для свойства <code>Height</code> и привязки сверху и снизу.
  
Ограничения всегда применяются и имеют приоритет.
+
Ограничения применяются всегда и имеют приоритет.
  
==Авторазмер и перемещение дочерних элементов управления==
+
==Автомасштаб и перемещение дочерних элементов управления==
  
 
Когда ''AutoSize=false'', вы можете размещать и перемещать элементы управления свободно:
 
Когда ''AutoSize=false'', вы можете размещать и перемещать элементы управления свободно:
Line 89: Line 84:
  
 
----
 
----
--[[User:Zoltanleo|Zoltanleo]] 22:53, 26 September 2018 (CEST): на самом деле, перемещаются границы родительского элемента управления так, чтобы дочерние элементы управления с фиксированной относительно друг друга позицией полностью умещались на родительском. При этом родительский элемент управления будет иметь минимально возможный размер. Таким образом, кнопки "перемещаются" относительно верхнего левого угла родительского элемента управления.
+
[[User:Zoltanleo|Прим.переводчика]]: на самом деле, перемещаются границы родительского элемента управления так, чтобы дочерние элементы управления с фиксированной относительно друг друга позицией полностью умещались на родительском. При этом родительский элемент управления будет иметь минимально возможный размер. Таким образом, кнопки "перемещаются" относительно верхнего левого угла родительского элемента управления.
 
----
 
----
  
Line 95: Line 90:
 
[[Image:Autosize panel on.png]]
 
[[Image:Autosize panel on.png]]
  
Обе кнопки на панели были перемещены влево и кверху на одно и то же значение так, чтобы сверху и слева не оставалось свободного пространства. Если будут установлены свойства ''BorderSpacing>0'' (у кнопок) или ''Panel.ChildSizing.LeftRightSpacing>0'' (у панели), то кнопки будут перемещены так, чтобы предопределенный [в упомянутых выше свойствах] зазор был задействован.
+
Обе кнопки на панели были перемещены влево и кверху на одно и то же значение так, чтобы сверху и слева не оставалось свободного пространства. Если будут установлены свойства ''BorderSpacing>0'' (у кнопок) или ''Panel.ChildSizing.LeftRightSpacing>0'' (у панели), то кнопки будут перемещены так, чтобы предопределенный в упомянутых выше свойствах зазор был задействован.
  
 
Могут быть перемещены дочерние элементы управления только со следующими свойствами:
 
Могут быть перемещены дочерние элементы управления только со следующими свойствами:
Line 103: Line 98:
 
* Align=alNone
 
* Align=alNone
  
Перемещение дочерних элементов управления зависит от свойства [[Autosize_/_Layout#Layout|ChildSizing.Layout]]. Разметка применяется в методе ''TWinControl.AlignControls'', который может быть полностью или частично переопределен. Например, ''TToolBar'' переопределяет ''ControlsAligned'', чтобы разместить все элементы управления со значением свойства ''Align=alCustom'', и задает разметку для перемещения на следующие линии не "вписавшимся" [в родительский контрол] [дочерним] элементам управления.
+
Перемещение дочерних элементов управления зависит от свойства [[Autosize_/_Layout#Layout|ChildSizing.Layout]]. Разметка применяется в методе ''TWinControl.AlignControls'', который может быть полностью или частично переопределен. Например, ''TToolBar'' переопределяет ''ControlsAligned'', чтобы разместить все элементы управления со значением свойства ''Align=alCustom'', и задает разметку для перемещения на следующие линии не "вписавшимся" в родительский контрол дочерним элементам управления.
  
[Родительские] элементы управления могут отключать перемещение дочерних элементов управления установкой [у свойства] ''ControlStyle'' флагов  ''csAutoSizeKeepChildLeft'' и ''csAutoSizeKeepChildTop'' (начиная с 0.9.29).
+
Родительские элементы управления могут отключать перемещение дочерних элементов управления установкой у свойства ''ControlStyle'' флагов  ''csAutoSizeKeepChildLeft'' и ''csAutoSizeKeepChildTop'' (начиная с 0.9.29).
  
==Авторазмер и формы==
+
==Автомасштаб и формы==
  
Формы без Parent [родительского элемента управления] управляются диспетчером окон и, следовательно, не могут свободно размещены или перемещены. Изменение размера [в RunTime] является лишь рекомендацией, и может быть проигнорировано диспетчером окон. Например, вы можете устанавливать ширину формы 1000 [px], а widgetset в ответ изменит размер к 800 [px]. Если вы устанавливаете [свойство] ''Witdh'' в [событии формы] ''OnResize'', то можете создать бесконечную петлю. Вот почему LCL TForm отключает ''AutoSize'', когда widgetset изменяет размеры формы.
+
Формы без Parent родительского элемента управления управляются диспетчером окон и, следовательно, не могут свободно размещены или перемещены. Изменение размера в RunTime является лишь рекомендацией, и может быть проигнорировано диспетчером окон. Например, вы можете устанавливать ширину формы 1000 px, а widgetset в ответ изменит размер к 800 px. Если вы устанавливаете свойство ''Witdh'' в событии формы ''OnResize'', то можете создать бесконечное зацикливание. Вот почему LCL TForm отключает ''AutoSize'', когда widgetset изменяет размеры формы.
  
Это означает, что [действие свойства] ''AutoSize'' для форм приостанавливается, когда пользователь изменяет размер формы или если диспетчеру окон не нравятся [текущие] границы [окна]. Например, некоторые диспетчеры окон в Linux имеют такие фишки, как магнитные [("прилипающие")] края, которые изменяют размеры [текущего] окна в привязке к другим окнам.
+
Это означает, что действие свойства ''AutoSize'' для форм приостанавливается, когда пользователь изменяет размер формы или если диспетчеру окон не нравятся текущие границы окна. Например, некоторые диспетчеры окон в Linux имеют такие фишки, как "прилипающие" края, которые изменяют размеры текущего окна в привязке к другим окнам.
  
===Принудительная установка авторазмера формы===
+
===Принудительная установка автомасштабирования формы===
Вы можете выставить новое [значение свойства] ''AutoSize'', выполнив:
+
Вы можете выставить новое значение свойства ''AutoSize'', выполнив:
  
<syntaxhighlight>Form1.AutoSize := False;
+
<syntaxhighlight lang="pascal">
 +
Form1.AutoSize := False;
 
Form1.AutoSize := True;</syntaxhighlight>
 
Form1.AutoSize := True;</syntaxhighlight>
  
===Расчет размера "авторазмерной" формы заранее===
+
===Расчет размера формы с "автомасштабом" заранее===
  
При размещении "авторазмерной" формы [(очевидно, имеется ввиду ''Form1.AutoSize=True'')] вам может потребоваться [получить] размер формы, прежде чем показывать ее. Для [установки] авторазмера требуется дескриптор [хэндл окна]. Вы можете рассчитать размер формы прежде, чем ее показывать, с помощью:
+
При размещении формы с "автомасштабом" (очевидно, имеется ввиду ''Form1.AutoSize=True'') вам может потребоваться получить размер формы, прежде чем показывать ее. Для установки автомасштаба требуется дескриптор (хэндл окна). Вы можете рассчитать размер формы прежде, чем ее показывать, с помощью:
  
<syntaxhighlight>Form1.HandleNeeded;
+
<syntaxhighlight lang="pascal">
 +
Form1.HandleNeeded;
 
Form1.GetPreferredSize(PreferredWidth,PreferredHeight);</syntaxhighlight>
 
Form1.GetPreferredSize(PreferredWidth,PreferredHeight);</syntaxhighlight>
  
'''Примечание''': Диспетчер окон и события формы могут изменять размер [окна]. Предпочтительный размер не включает рамку окна формы. Это запланированная особенность.
+
{{Note| Диспетчер окон и события формы могут изменять размер окна. Предпочтительный размер не включает рамку окна формы. Это запланированная особенность.}}
 +
<br /><br />
  
=Привязка сторон=
+
=Привязка сторон (Anchoring)=
  
Элементы управления [для привязки к] четырем сторонам имеют [свойство ''Anchors'' с возможными значениями]: ''akLeft'', ''akTop'', ''akRight'' и ''akBottom''. Каждая сторона может быть привязана к родителю или к стороне другого собрата (элемент управления с одним и тем же родителем). Привязка означает '''сохранение расстояния''' [между привязанными элементами управления]. По умолчанию [значение свойства] ''Anchors = [akLeft, akTop]''. Вертикальные привязки не зависят от горизонтальных привязок. Некоторые свойства, такие как ''Align'' и ''Parent.AutoSize'' имеют более высокий приоритет, и могут изменять поведение.
+
Элементы управления для привязки к четырем сторонам имеют свойство ''Anchors'' с возможными значениями: ''akLeft'', ''akTop'', ''akRight'' и ''akBottom''. Каждая сторона может быть привязана к родителю или к стороне другого собрата (элемент управления с одним и тем же родителем). Привязка означает '''сохранение расстояния''' между привязанными элементами управления. По умолчанию значение свойства ''Anchors = [akLeft, akTop]''. Вертикальные привязки не зависят от горизонтальных привязок. Некоторые свойства, такие как ''Align'' и ''Parent.AutoSize'' имеют более высокий приоритет, и могут изменять поведение.
  
 
==Привязка к родителю или nil==
 
==Привязка к родителю или nil==
Line 138: Line 136:
 
Существует четыре комбинации akLeft, akRight (akTop, akBottom):
 
Существует четыре комбинации akLeft, akRight (akTop, akBottom):
  
*'''akLeft, no akRight''': '''Left''' контрола фиксирован и не [может быть] изменен LCL. Правая сторона не закреплена, поэтому она следует за левой стороной. Это означает, что '''Width''' также сохраняется.
+
*'''akLeft, no akRight''': '''Left''' контрола фиксирован и не может быть изменен LCL. Правая сторона не закреплена, поэтому она следует за левой стороной. Это означает, что '''Width''' также сохраняется.
*'''akLeft and akRight''': '''Left''' элемента управления фиксирован и не [может быть] изменен LCL. Правая сторона привязана к правой стороне Родителя. Это означает, что если Родитель увеличен на 100 пикселей, тогда '''Width''' контрола также будет увеличена на 100 пикселей.
+
*'''akLeft and akRight''': '''Left''' элемента управления фиксирован и не может быть изменен LCL. Правая сторона привязана к правой стороне Родителя. Это означает, что если Родитель увеличен на 100 пикселей, тогда '''Width''' контрола также будет увеличена на 100 пикселей.
 
*'''akRight, no akLeft''': левая сторона управления не закреплена, поэтому она будет следовать за ее правой стороной. Правая сторона закреплена. Это означает, что если Родитель увеличится на 100 пикселей, тогда контроле перемещается вправо на 100 пикселей.
 
*'''akRight, no akLeft''': левая сторона управления не закреплена, поэтому она будет следовать за ее правой стороной. Правая сторона закреплена. Это означает, что если Родитель увеличится на 100 пикселей, тогда контроле перемещается вправо на 100 пикселей.
 
*'''no akLeft and no akRight''': ни одна из сторон не закреплена. Положение центра контрола масштабируется с родителем. Например, если контрол находится в середине родительского элемента, а родительский элемент увеличен на 100 пикселей, тогда контрол перемещается на 50 пикселей вправо.
 
*'''no akLeft and no akRight''': ни одна из сторон не закреплена. Положение центра контрола масштабируется с родителем. Например, если контрол находится в середине родительского элемента, а родительский элемент увеличен на 100 пикселей, тогда контрол перемещается на 50 пикселей вправо.
Line 145: Line 143:
 
===Изменение размера родителя с привязанным контролом===
 
===Изменение размера родителя с привязанным контролом===
  
При изменении размера родителя все привязанные дочерние контролы перемещаются и/или изменяются по размеру сразу, пока не будет отключено [свойство] AutoSizing. Например, AutoSizing отключается во время загрузки формы и при создании формы.
+
При изменении размера родителя все привязанные дочерние контролы перемещаются и/или изменяются по размеру сразу, пока не будет отключено свойство AutoSizing. Например, AutoSizing отключается во время загрузки формы и при создании формы.
  
 
GroupBox с кнопкой: [[Image:Anchors1.png]]
 
GroupBox с кнопкой: [[Image:Anchors1.png]]
  
Когда GroupBox увеличивается [в размере], расстояние до привязанной стороны сохраняется:
+
Когда GroupBox увеличивается в размере, расстояние до привязанной стороны сохраняется:
  
 
С akLeft, без akRight: [[Image:Anchors akLeft.png]]
 
С akLeft, без akRight: [[Image:Anchors akLeft.png]]
Line 163: Line 161:
  
 
'''На заметку:'''
 
'''На заметку:'''
*Загрузка формы похожа на один большой SetBounds. Во время загрузки свойства задаются с использованием значений [, сохраненных в файле формы] lfm. Имейте в виду, что из-за предков и фреймов может быть несколько файлов lfm. После загрузки LCL активирует autosizing. Привязанные контролы используют ограничение в конце загрузки. Любой шаг между ними игнорируется.
+
*Загрузка формы похожа на один большой SetBounds. Во время загрузки свойства задаются с использованием значений , сохраненных в файле формы lfm. Имейте в виду, что из-за предков и фреймов может быть несколько файлов lfm. После загрузки LCL активирует autosizing. Привязанные контролы используют ограничение в конце загрузки. Любой шаг между ними игнорируется.
 
*Для пользовательских контролов часто лучше устанавливать AnchorSides вместо Anchors.
 
*Для пользовательских контролов часто лучше устанавливать AnchorSides вместо Anchors.
  
Line 169: Line 167:
  
 
При изменении ширины привязанного элемента управления, например, через Object Inspector или через код ''Button1.Width:=3'', вы можете увидеть разницу между привязкой к "родителю" и привязкой к "nil". Привязка к родителю будет  изменять размер и перемещать Button1, а привязка к nil будет только изменять размер. Например:
 
При изменении ширины привязанного элемента управления, например, через Object Inspector или через код ''Button1.Width:=3'', вы можете увидеть разницу между привязкой к "родителю" и привязкой к "nil". Привязка к родителю будет  изменять размер и перемещать Button1, а привязка к nil будет только изменять размер. Например:
 +
 
====Привязка к nil====
 
====Привязка к nil====
  
 
[[Image:Anchored_right_nil_resize1.png]] Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=nil  
 
[[Image:Anchored_right_nil_resize1.png]] Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=nil  
  
[[Image:Anchored_right_nil_resize2.png]] Установка ширины на меньшее значение приведет к сужению кнопки, сохраняя [значение] ''Left'' кнопки, увеличивая расстояние от правой стороны [кнопки до правого края].
+
[[Image:Anchored_right_nil_resize2.png]] Установка ширины на меньшее значение приведет к сужению кнопки, сохраняя значение ''Left'' кнопки, увеличивая расстояние от правой стороны кнопки до правого края.
  
[[Image:Anchored_right_nil_resize3.png]] При изменении размера Groupbox кнопка сохранит новое расстояние [до правого края].
+
[[Image:Anchored_right_nil_resize3.png]] При изменении размера Groupbox кнопка сохранит новое расстояние до правого края.
  
'''Объяснение:''' установка [значения] '''Width''' [кнопки] эквивалентна вызову SetBounds('''Left''',Top,'''NewWidth''',Height). Вот почему [значение] '''Left''' сохраняется. Это совместимо с [поведением контролов в] Delphi.
+
'''Объяснение:''' установка значения '''Width''' кнопки эквивалентна вызову SetBounds('''Left''',Top,'''NewWidth''',Height). Вот почему значение '''Left''' сохраняется. Это совместимо с поведением контролов в Delphi.
  
 
====Привязка к родителю====
 
====Привязка к родителю====
 
[[Image:Anchored_right_parent_resize1.png]] Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=Button1.Parent
 
[[Image:Anchored_right_parent_resize1.png]] Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=Button1.Parent
  
[[Image:Anchored_right_parent_resize2.png]] Установка [значения] ''Width'' на меньшее значение приведет к сужению кнопки, сохранив расстояние [от ее правой границы до края компонента-родителя] и изменив [значение] ''Left'' кнопки.
+
[[Image:Anchored_right_parent_resize2.png]] Установка значения ''Width'' на меньшее значение приведет к сужению кнопки, сохранив расстояние от ее правой границы до края компонента-родителя и изменив значение ''Left'' кнопки.
  
 
==Привязка к соседу==
 
==Привязка к соседу==
  
Вы можете привязываться к соседним элементам управления. Следующий пример показывает[, что]:
+
Вы можете привязываться к соседним элементам управления. Следующий пример показывает, что:
*вы можете привязать левый [край] label'а к левому краю кнопки
+
*вы можете привязать левый край label'а к левому краю кнопки
 
*привязать верхний край  label'а к нижнему краю кнопки
 
*привязать верхний край  label'а к нижнему краю кнопки
 
*привязать центр label'а к центру кнопки<br />
 
*привязать центр label'а к центру кнопки<br />
Line 197: Line 196:
 
[[Image:Anchoreditor.png]]
 
[[Image:Anchoreditor.png]]
  
==Пограничный интервал==
+
==Зазор==
  
Свойства BorderSpacing управляют минимальным количеством пространства вокруг элемента управления. Свойства:
+
Свойство BorderSpacing(зазор) управляет минимальным количеством пространства вокруг элемента управления. Свойства:
  
*'''Around''': эта величина в пикселах добавляется к [каждому значению] Left, Top, Right, Bottom [элемента управления].
+
*'''Around''': эта величина в пикселах, которая добавляется к каждому значению Left, Top, Right, Bottom элемента управления.
*'''Left''': пространство в пикселах с левой стороны элемента управления
+
*'''Left''': зазор в пикселах с левой стороны элемента управления
*'''Top''': пространство в пикселах сверху элемента управления
+
*'''Top''': зазор в пикселах сверху элемента управления
*'''Right''': пространство в пикселах с правой стороны элемента управления
+
*'''Right''': зазор в пикселах с правой стороны элемента управления
*'''Bottom''': пространство в пикселах под элементом управления
+
*'''Bottom''': зазор в пикселах под элементом управления
*'''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.
+
*'''InnerBorder''': это зазор в пикселях, добавляется дважды к оптимальной ширине и высоте. Некоторые элементы управления переопределяют вычисление и игнорируют это свойство. Пример, где он работает, - TButton. С помощью InnerBorder вы можете сделать кнопку больше, чем необходимо.
*'''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.
+
*'''CellAlignHorizontal''': Этот параметр используется в табличных макетах, таких как ChildSizing.Layout=cclLeftToRightThenTopToBottom. Если элемент управления меньше ячейки таблицы, это свойство определяет, как выровнять элемент управления: слева ccaLeftTop, справа ccaRightBottom или посередине ccaCenter.
*'''CellAlignVertical''': same as CellAlignHorizontal but for vertical alignment.
+
*'''CellAlignVertical''': так же, как CellAlignHorizontal, но для вертикального выравнивания.
  
===BorderSpacing rules===
+
===Правила зазоров===
  
*Around is added to Left,Top,Right,Bottom borderspacing
+
*Значение Around добавляется к зазору для Left,Top,Right,Bottom элемента управления.
*The space can be even bigger, if the controls have constraints that don't allow to expand.
+
*Зазор может быть еще больше, если элементы управления имеют ограничения, которые не позволяют им растягиваться.
  
====Anchoring to the opposite side====
+
====Привязка к противоположной стороне====
  
For example right side of A to left side of B.
+
Например, правая сторона A к левой стороне B.
  
Both borderspacings of A and B are used.
+
Используются обе границы A и B.
  
*The horizontal space between two controls (LeftControl, RightControl on Parent) is the maximum of
+
*Горизонтальный зазор между двумя элементами управления (LeftControl, RightControl на общем родителе) он максимален, если:
 
**LeftControl.BorderSpacing.Right + LeftControl.BorderSpacing.Around
 
**LeftControl.BorderSpacing.Right + LeftControl.BorderSpacing.Around
 
**RightControl.BorderSpacing.Left + RightControl.BorderSpacing.Around
 
**RightControl.BorderSpacing.Left + RightControl.BorderSpacing.Around
 
**Parent.ChildSizing.HorizontalSpacing
 
**Parent.ChildSizing.HorizontalSpacing
*The vertical space works analog: between two controls (TopControl, BottomControl on Parent) is the maximum of
+
*Вертикальный зазор работает аналогично: между двумя элементами управления (TopControl, BottomControl на общем родителе) он максимален, если:
 
**TopControl.BorderSpacing.Bottom + TopControl.BorderSpacing.Around
 
**TopControl.BorderSpacing.Bottom + TopControl.BorderSpacing.Around
 
**BottomControl.BorderSpacing.Top + BottomControl.BorderSpacing.Around
 
**BottomControl.BorderSpacing.Top + BottomControl.BorderSpacing.Around
 
**Parent.ChildSizing.VerticalSpacing
 
**Parent.ChildSizing.VerticalSpacing
  
For 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.
+
Например:
 +
*если LeftControl.BorderSpacing.Right=3 и LeftControl.BorderSpacing.Around=4, то между двумя элементами управления должно быть не менее 7px
 +
*если RightControl.BorderSpacing.Left=4 и RightControl.BorderSpacing.Around=4, то пространство будет не менее 8px
 +
*если Parent.ChildSizing.HorizontalSpacing=10, тогда пространство будет не менее 10px
  
====Anchoring to the same side====
+
====Привязка к этой же стороне====
  
For example right side of A to right side of B.
+
Например, правая сторона A к правой стороне B.
  
*Only borderspacings of A is used.
+
*Задействуется только зазор у границы А.
*Parent.ChildSizing.Horizontal/VerticalSpacing are not used.
+
*Свойство Parent.ChildSizing.Horizontal/VerticalSpacing не используется.
  
====Anchoring to center====
+
====Привязка к центру====
  
For example center of A to center of B.
+
Например, центр А привязан к центру В.
  
No borderspacing is used and no Parent.ChildSizing.Horizontal/VerticalSpacing is used.
+
Не задействуются ни зазор, ни свойство Parent.ChildSizing.Horizontal/VerticalSpacing.
  
====Example====
+
====Пример====
  
A common example is anchoring a Label to an Edit.
+
Общим примером является привязка Label'а к Edit.<br />
  
[[Image:BorderSpacing Anchors.png]]
+
[[Image:BorderSpacing Anchors.png]]<br />
  
The 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.
+
Центр Label'а вертикально привязан к Edit. Левая сторона Edit'а привязана к правой стороне Label. Оба имеют BorderSpacing.Around=6. Это приводит к наличию зазора в 6px между Label'ом и Edit'ом и наличию зазора в 6px слева от Label'а, а также наличию зазора в 6px справа от Edit. Также еще существует 6 пикселей зазора выше и ниже Edit.
  
*The left space between a control and its parent (Label1 on GroupBox1) is the maximum of
+
*Зазор слева между элементом управления и его родителем (Label1 к GroupBox1) является максимальным, когда
 
**Label1.BorderSpacing.Left + Label1.BorderSpacing.Around
 
**Label1.BorderSpacing.Left + Label1.BorderSpacing.Around
 
**GroupBox1.ChildSizing.LeftTopSpacing
 
**GroupBox1.ChildSizing.LeftTopSpacing
  
*The right space between a control and its parent (Edit1 on GroupBox1) is the maximum of
+
*Зазор справа между элементом управления и его родителем (Edit1 к GroupBox1) является максимальным, когда
 
**Edit1.BorderSpacing.Right + Edit1.BorderSpacing.Around
 
**Edit1.BorderSpacing.Right + Edit1.BorderSpacing.Around
 
**GroupBox1.ChildSizing.RightBottomSpacing
 
**GroupBox1.ChildSizing.RightBottomSpacing
  
*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.
+
*Когда центр элемента управления привязан к другому элементу управления, например, вышеуказанный Label центрирован по вертикали к  Edit1, тогда все остальные зазоры игнорируются.
  
*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
+
*Когда левая сторона элемента управления привязана к левой стороне другого элемента управления (т.е., они выровнены по левой стороне), то расстояние между обеими левыми сторонами является
 
**Control1.BorderSpacing.Left + Control1.BorderSpacing.Around
 
**Control1.BorderSpacing.Left + Control1.BorderSpacing.Around
  
  
Here is a more complex example:
+
Вот более сложный пример:
  
 
[[Image:Borderspacing anchors2.png]]
 
[[Image:Borderspacing anchors2.png]]
  
The important parts of the lfm code:
+
Важные части кода lfm:
  
<syntaxhighlight> object GroupBox1: TGroupBox
+
<syntaxhighlight lang="pascal">
 +
  object GroupBox1: TGroupBox
 
     AutoSize = True
 
     AutoSize = True
 
     Caption = 'GroupBox1'
 
     Caption = 'GroupBox1'
Line 339: Line 342:
 
   end</syntaxhighlight>
 
   end</syntaxhighlight>
  
===BorderSpacing and Align===
+
===Зазор и выравнивание===
  
BorderSpacing works with Align. In the example below there is a Memo1 with Align=alTop and a Memo2 with Align=alCLient.  
+
Зазор работает с выравниванием. В приведенном ниже примере есть Memo1 с Align=alTop и Memo2 с Align=alCLient.
*Normally the two Memos would fill the whole GroupBox.  
+
*Обычно два Memo заполняют весь GroupBox.
*But the Memo1 has BorderSpacing.Around=10, so there 10 pixel space around Memo1.  
+
*Но Memo1 имеет BorderSpacing.Around=10, так что вокруг Memo1 будет присутствовать зазор в 10 пикселей.
*The Memo2 has BorderSpacing.Top=20. The space between Memo1 and Memo2 is the maximum, which is the 20 from Memo2.  
+
*Memo2 имеет BorderSpacing.Top=20. Зазор между Memo1 и Memo2 будет максимальным, который от Memo1 до Memo2 составит 20px.
*Memo2 has also BorderSpacing.Right=50 so there is 50 Pixel space right of Memo2.
+
*Memo2 также имеет и BorderSpacing.Right=50, поэтому справа от Memo2 имеется зазор в 50 пикселей.
*The GroupBox can define default space for all its child controls via ChildSizing.LeftRightSpacing/VerticalSpacing/HorizontalSpacing. In this example it does not (all 0).
+
*GroupBox может задавать зазор по умолчанию для всех своих дочерних элементов управления через значения свойств ChildSizing.LeftRightSpacing/VerticalSpacing/HorizontalSpacing. В этом примере их нет (все упомянутые значения равны 0).<br />
  
[[Image:Borderspacing align1.png]]
+
[[Image:Borderspacing align1.png]]<br /> <br />
  
=Align=
+
=Выравнивание (Aligned)=
  
The 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.
+
Свойство Align(выравнивание) работает почти так же, как в Delphi, и может использоваться для быстрого заполнения какой-нибудь области. Например, чтобы TListBox заполнил всю область своего родителя, установите 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.
+
Значения выравнивания alTop, alBottom, alLeft и alRight будут размещать элементы управления по возможности без перекрытия друг друга. Это означает, что все элементы управления свойства Align со значением ''alLeft, alTop, alBottom, alRight'' не будут перекрываться, если есть достаточно места.
  
The algorithm works as follows:
+
Алгоритм работает следующим образом:
*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.
+
* Сначала все элементы управления с помощью значения свойства alTop помещаются в верхнюю часть клиентской области. Если имеется несколько элементов управления с помощью alTop, последний добавленный/перемещенный будет помещен выше всех. Алгоритм будет стараться избегать перекрытия и сохранять высоту элемента управления, пока ширина всех элементов остается максимальной. Стороны привязки левой, верхней и правой сторон игнорируются. Нижняя сторона привязки работает нормально. Зазор и значение свойства Parent.ChildSize просчитываются, поэтому вы можете задавать зазор вокруг каждого выровненного элемента управления.
*Then all controls with alBottom are put to the bottom of the client area. Otherwise it works analog to alTop.
+
*Затем все элементы управления с помощью значения свойства alBottom помещаются в нижнюю часть клиентской области. В противном случае оно работает аналогично alTop.
*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.
+
*Потом все элементы управления с помощью значения свойства alLeft помещаются слева от клиентской области между элементами управления alTop и alBottom. В противном случае оно работает аналогично alTop.
*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.
+
*Затем все элементы управления с помощью значения свойства alRight помещаются справа от клиентской области между элементами управления alTop и alBottom. В противном случае оно работает аналогично alTop.
*If there is a control with alClient it will fill the remaining client.
+
*Если есть элемент управления с установленным свойством alClient, он заполнит оставшуюся часть клиентской области.
*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.
+
*Если имеется более одного элемента управления с установленным свойством alClient, они будут помещаться в одно и то же положение, перекрывая друг друга. Используйте свойство Visibility, чтобы определить, какой из них будет показан. <br /><br />
  
 
[[Image:Autosize_align.png]]
 
[[Image:Autosize_align.png]]
  
==Align and BorderSpacing==
+
==Выравнивание и зазоры==
  
The space of BorderSpacing and of the parent's ChildSizing is applied to aligned controls. The memo below has Align=alClient.
+
Величина свойства BorderSpacing и свойства ChildSize родителя применяется к выравниваемым элементам управления. Элемент управления memo ниже имеет Align=alClient.<br />
  
 +
----
 +
[[User:Zoltanleo|Прим.переводчика]]: Ох, уж эти языковые особенности. Автор, очевидно, имел в виду следующее: даже если у дочернего контрола выравнивание выставлено как Align=alClient, то он не будет заполнять собой контрол-родитель полностью, если его свойство BorderSpacing или свойство ChildSize родителя имеют ненулевое значение.
 +
----
 +
<br />
 
[[Image:Autosize align borderspacing.png]]
 
[[Image:Autosize align borderspacing.png]]
  
==Align and Anchoring==
+
==Выравнивание и Привязка==
  
The 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.
+
Свободная сторона выровненного элемента управления (напр., правая сторона '''Align=alLeft''') следует правилам привязки. Если привязка не установлена, тогда элемент управления будет сохранять значение своей '''Width'''. Если привязка установлена, то значение '''Width''' изменится.
  
==Align and AutoSize==
+
==Выравнивание и свойство AutoSize==
  
A 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''.
+
Элемент управления, выровненный посредством alLeft или alRight, растягивается по вертикали и будет использовать свою ширину, определенную на этапе проектирования формы. Если свойство ''AutoSize'' установлено в ''true'', то значение параметра ''Width'' будет оптимальной шириной. Кнопка снизу имеет ''Align=alRight'' и ''AutoSize=true''.<br />
  
 
[[Image:Autosize align autosize.png]]
 
[[Image:Autosize align autosize.png]]
  
==Align and parent AutoSize==
+
==Выравнивание и свойство AutoSize родителя==
  
A 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?  
+
Элемент управления, выровненный посредством alClient, заполняет оставшееся пространство. Родительский элемент управления со значением свойства ''AutoSize=true'' при этом будет растягиваться или сжиматься так, чтобы впритирку умещать на себе свои дочерние элементы. Что произойдет, если вы объедините эти два свойства? Скажем, вы положили кнопку с Align=alClient на groupbox с AutoSize=true?<br />
  
[[Image:Autosize nested1.png]]
+
[[Image:Autosize nested1.png]]<br />
  
The LCL uses the ''preferred size'' of the buttons and expands or shrinks the groupbox accordingly:
+
LCL использует ''предпочтительный размер'' кнопок и потому растягивает или сжимает groupbox:
  
[[Image:Autosize nested2.png]]
+
[[Image:Autosize nested2.png]]<br />
  
 
==alCustom==
 
==alCustom==
  
This 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.
+
Это значение Align существует для пользовательских алгоритмов AutoSize и обрабатывается LCL почти как alNone. Элементы управления с установленным значением alCustom не перемещаются LCL, но могут быть перемещены вашим пользовательским элементом управления. Для этого вы должны переопределить методы <code>CalculatePreferredSize</code> и <code>DoAutoSize</code>.
  
==Order of controls with same Align==
+
==Порядок расположения элементов управления с одинаковым значением Align==
  
Controls with same Align are added 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.
+
Элементы управления с одинаковым выравниванием добавляются в следующем порядке. Для alLeft элемент управления с наименьшим значением Left, для alTop - наименьшим значением Top, для alRight - наибольшая величина Left+Width, для alBottom - наибольшая величина Top+Height. Если два элемента управления имеют одну и ту же координату, последний из них одерживает победу (вызывая SetBounds или SetParent). Элементы управления могут переопределять CreateControlAlignList, чтобы изменить порядок или переопределить DoAlignChildControls для обработки всего Align.
  
Note: 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.
+
{{Note| до версии Lazarus 0.9.29 элементы управления размещались в Z-порядке. В некоторых случаях это приводило к переупорядочиванию элементов управления и должно было быть исправлено. Существует одна несовместимость: если вы добавили несколько элементов управления с выравниванием alTop или alLeft без указания границ, все элементы управления будут помещены в координаты 0.0, и, следовательно, последние добавленные окажутся поверх контролов, добавленных ранее.}}<br /><br />
  
=Layout=
+
=Разметка (Layout)=
  
==Rows, columns and lines==
+
==Строки, столбцы и строки==
  
You can align child controls in rows and columns using the ChildSizing properties. For example:
+
Вы можете выравнивать дочерние элементы управления в строках и столбцах, используя свойства ChildSize. Например:
  
 
*ChildSizing.Layout=cclLeftToRightThenTopToBottom
 
*ChildSizing.Layout=cclLeftToRightThenTopToBottom
 
*ChildSizing.ControlsPerLine=3
 
*ChildSizing.ControlsPerLine=3
*AutoSize=false (the groupbox does not resize to fit the child controls)
+
*AutoSize=false (не изменяет размеры, чтобы подстраиваться под дочерние элементы управления)<br />
  
 
[[Image:Autosize layout lefttoright.png]]
 
[[Image:Autosize layout lefttoright.png]]
  
The '''Layout''' property defaults to cclNone. If you set '''Layout''' to another value, every child, that has ''normal'' anchors, will be aligned. ''Normal'' anchors means:
+
Свойство '''Layout''' по умолчанию [имеет значение] cclNone. Если вы установите '''Layout''' в другое значение, каждый дочерний элемент, имеющий ''нормальные'' привязки, будет выровнен. ''Нормальные'' привязки означают:
 
*Anchors=[akLeft,akTop]
 
*Anchors=[akLeft,akTop]
 
*AnchorSide[akLeft].Control=nil
 
*AnchorSide[akLeft].Control=nil
Line 419: Line 426:
 
*Align=alNone
 
*Align=alNone
  
The 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).
+
Значение '''cclLeftToRightThenTopToBottom''' будет помещать первый дочерний элемент управление вверху [и] слева, второй - [вверху и] правее, и так далее. Это - '''линия'''. Свойство '''ControlsPerLine''' определяет, когда начинается новая строка. В приведенном выше примере каждая линия (строка) имеет 3 элемента управления. Существует [всего] 12 элементов управления, поэтому есть 4 линии (строки), каждая из которых имеет [по] 3 элемента управления (столбцы).
If ''ControlsPerLine'' is 0 it means unlimited controls per line - there would be only one row with all childs.
+
Если ''ControlsPerLine'' равен 0, это означает неограниченное количество элементов управления в строке - будет только одна строка со всеми дочерними элементами.
  
You 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.
+
Вы можете видеть, что строки имеют разные размеры, каждая строка имеет размер самого большого элемента управления и что элементы управления изменяют размеры до ширины столбца. Между строками нет пробела. Пространство в изображении определяется используемой темой, а не [приходит] из LCL.
  
==Fixed space between rows and columns==
+
==Фиксированные зазоры между строками и столбцами==
  
You can add space between with these properties:
+
Вы можете добавить зазоры между [строками и столбцами] этими свойствами:
  
*ChildSizing.VerticalSpacing - Space between rows
+
*ChildSizing.VerticalSpacing - зазор между строками
*ChildSizing.HorizontalSpacing - Space between columns
+
*ChildSizing.HorizontalSpacing - зазор между столбцами
*ChildSizing.LeftRightSpacing - Space on the left and right of ''all'' columns
+
*ChildSizing.LeftRightSpacing - зазор между левой  и правой [стороной] ''всех'' столбцов
*ChildSizing.TopBottomSpacing - Space above and below of ''all'' columns
+
*ChildSizing.TopBottomSpacing - зазор выше и ниже ''всех'' столбцов
  
The above example with
+
Выше приведенный пример с [параметрами]:<br />
ChildSizing.VerticalSpacing=6, ChildSizing.HorizontalSpacing=15, ChildSizing.LeftRightSpacing=30, ChildSizing.TopBottomSpacing=10, AutoSize=true
+
ChildSizing.VerticalSpacing=6,<br />
 +
ChildSizing.HorizontalSpacing=15,<br />
 +
ChildSizing.LeftRightSpacing=30,<br />
 +
ChildSizing.TopBottomSpacing=10,<br />
 +
AutoSize=true<br />
  
 
[[Image:Autosize layout parentspacing.png]]
 
[[Image:Autosize layout parentspacing.png]]
  
Additionally you can add individual space for each control with its BorderSpacing properties.
+
Кроме того, вы можете добавить зазор для каждого элемента управления отдельно с [помощью] его свойства BorderSpacing.
  
==Enlarge==
+
==Растяжение==
  
The 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.
+
Приведенный выше пример изменяет размер GroupBox до необходимых размеров. Если ваш GroupBox имеет фиксированный размер или если он не является свободно изменяемым, например, если GroupBox должен заполнять всю ширину формы, то дочерние элементы должны растягиваться. Существует несколько режимов. Режим по умолчанию ''ChildSizing.EnlargeHorizontal=crsAnchorAligning'' запрещает что-либо растягивать. Зазоры с правой стороны не будут использоваться.
  
*crsAnchorAligning - do not use the extra space
+
*<tt>crsAnchorAligning</tt> - не использует дополнительные зазоры
*crsScaleChilds - multiply the width/height with the same factor
+
*<tt>crsScaleChilds</tt> - умножает ширину/высоту на тот же коэффициент
*crsHomogeneousChildResize - add to each width/height the same amount
+
*<tt>crsHomogeneousChildResize</tt> - добавляет к каждой ширине/высоте ту же величину
*crsHomogeneousSpaceResize - add to each space between the childs the same amount
+
*<tt>crsHomogeneousSpaceResize</tt> - добавляет к каждому зазору между дочерними элементами ту же величину
  
 
===crsScaleChilds===
 
===crsScaleChilds===
  
ChildSizing.EnlargeHorizontal=crsScaleChilds, ChildSizing.EnlargeVertical=crsScaleChilds, AutoSize=false
+
<tt>ChildSizing.EnlargeHorizontal=crsScaleChilds</tt><br /> <tt>ChildSizing.EnlargeVertical=crsScaleChilds</tt><br /> <tt>AutoSize=false</tt><br />
  
 
[[Image:Autosize layout scalechilds.png]]
 
[[Image:Autosize layout scalechilds.png]]
  
For example if the ClientWidth is twice as big as needed, then every child will be twice as big.
+
Например, если значение ClientWidth вдвое больше необходимого, то каждый дочерний элемент будет в два раза больше.
  
 
===crsHomogeneousChildResize===
 
===crsHomogeneousChildResize===
  
ChildSizing.EnlargeHorizontal=crsHomogeneousChildResize, ChildSizing.EnlargeVertical=crsHomogeneousChildResize, AutoSize=false
+
<tt>ChildSizing.EnlargeHorizontal=crsHomogeneousChildResize</tt><br /> <tt>ChildSizing.EnlargeVertical=crsHomogeneousChildResize</tt><br /> <tt>AutoSize=false</tt><br />
  
 
[[Image:Autosize layout homogeneouschildresize.png]]
 
[[Image:Autosize layout homogeneouschildresize.png]]
  
For example if the ClientWidth is 30 pixel bigger than needed, then every child will be 10 pixel broader.
+
Например, если ClientWidth на 30 пикселей больше, чем нужно, то каждый дочерний элемент будет на 10 пикселей шире.
  
 
===crsHomogeneousSpaceResize===
 
===crsHomogeneousSpaceResize===
  
ChildSizing.EnlargeHorizontal=crsHomogeneousSpaceResize, ChildSizing.EnlargeVertical=crsHomogeneousSpaceResize, AutoSize=false
+
<tt>ChildSizing.EnlargeHorizontal=crsHomogeneousSpaceResize</tt><br /> <tt>ChildSizing.EnlargeVertical=crsHomogeneousSpaceResize</tt><br/> <tt>AutoSize=false</tt><br />
  
 
[[Image:Autosize layout homogeneousspaceresize.png]]
 
[[Image:Autosize layout homogeneousspaceresize.png]]
  
For example if the ClientWidth is 40 pixel bigger than needed, there will be 10 pixel space on the left, right and between each child.
+
Например, если ClientWidth на 40 пикселов больше, чем необходимо, появится [дополнительно по] 10 пикселей зазора слева, справа и между каждым дочерним элементом.
  
==Shrink==
+
==Сжатие==
  
Shrinking works similarly to enlarging. You can set different modes if there is not enough space for controls. '''ShrinkHorizontal''', '''ShrinkVertical'''.
+
Сжатие работает аналогично растяжению. Вы можете установить разные режимы, если для элементов управления недостаточно места. '''ShrinkHorizontal''', '''ShrinkVertical'''.
  
==Individual cells==
+
==Отдельные ячейки==
  
In 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'''.
+
В приведенных выше примерах все элементы управления изменялись одинаково, каждый заполнял всю ''ячейку''. ''Ячейка'' - это пространство в определенной строке и столбце. Обычно элемент управления заполняет все пространство ячейки. Это можно изменить с помощью свойств '''BorderSpacing.CellAlignHorizontal''' и '''BorderSpacing.CellAlignVertical'''.
  
For example set the ''BorderSpacing.CellAlignHorizontal'' of the fifth button to '''caCenter''' you will get this:
+
Например, установите ''BorderSpacing.CellAlignHorizontal'' пятой кнопки в '''caCenter''' [и] вы получите следующее:
  
 
[[Image:Autosize layout cellhorizontal cacenter.png]]
 
[[Image:Autosize layout cellhorizontal cacenter.png]]
  
There are four possible values for CellAlignHorizontal/CellAlignVertical:
+
Существует четыре возможных значения для CellAlign Horizontal/CellAlign Vertical:
  
*caFill: the child control fills the whole width (height) of the cell
+
*<tt>caFill</tt>: дочерний элемент управления заполняет всю ширину (высоту) ячейки
*caCenter: the child control uses its preferred width (height) and will be centered in the cell
+
*<tt>caCenter</tt>: дочерний элемент управления использует свою оптимальную ширину (высоту) и будет центрироваться в ячейке
*caLeftTop: the child control uses its preferred width (height) and will be leftaligned in the cell
+
*<tt>caLeftTop</tt>: дочерний элемент управления использует свою оптимальную ширину (высоту) и выравнивается в ячейке слева
*caRightBottom: the child control uses its preferred width (height) and will be rightaligned in the cell
+
*<tt>caRightBottom</tt>: дочерний элемент управления использует свою оптимальную ширину (высоту) и будет в ячейке выравниваться по правому краю
  
 
[[Image:Autosize layout cellalign.png]]
 
[[Image:Autosize layout cellalign.png]]
 +
<br /><br />
  
=Custom layout with OnResize / OnChangeBounds=
+
=Пользовательская разметка через OnResize/OnChangeBounds=
  
Sometimes 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.
+
Иногда разметка LCL недостаточно [оптимальна]. В приведенном ниже примере показан GroupBox1 со списком ListBox1 и Memo1. ListBox1 должен заполнить одну треть пространства, Memo1 - забрать все остальное.<br />
  
 
[[Image:Autosize_onresize.png]]
 
[[Image:Autosize_onresize.png]]
  
Whenever the GroupBox is resized the ListBox1.Width should be one third. To achieve this set the OnResize event of the GroupBox1 to:
+
Всякий раз, когда размер GroupBox изменяется, ListBox1.Width должен составлять одну треть. Для этого определите событие OnResize для GroupBox1:
  
<syntaxhighlight>procedure TForm1.GroupBox1Resize(Sender: TObject);
+
<syntaxhighlight lang="pascal">
 +
procedure TForm1.GroupBox1Resize(Sender: TObject);
 
begin
 
begin
 
   ListBox1.Width := GroupBox1.ClientWidth div 3;
 
   ListBox1.Width := GroupBox1.ClientWidth div 3;
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
===Common mistake: Wrong OnResize event===
+
===Общая ошибка: неправильное событие OnResize===
  
Do 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.
+
Не помещайте ''весь'' свой код изменения размера [элементов управления] в событие Form OnResize. Событие Form OnResize вызывается только при изменении размера формы. Дочерние элементы управления (напр., GroupBox1) изменятся позже, поэтому GroupBox1.ClientWidth все еще [будет] иметь старое значение во время события FormResize. Вы должны использовать событие GroupBox1.OnResize, чтобы реагировать на изменения GroupBox1.ClientWidth.
  
===Common mistake: Width instead of ClientWidth, AdjustClientRect===
+
===Общая ошибка: Width вместо ClientWidth, AdjustClientRect===
  
The 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:
+
[Свойство] Width - это размер [элемента управления], включая рамку. [Свойство] ClientWidth - это внутренняя ширина [элемента управления] без рамки. Некоторые элементы управления, такие как TPanel, рисуют еще одну рамку. Потом вы используете AdjustClientRect. Тот же пример, но вместо GroupBox1 на Panel1 находится ListBox1:
  
<syntaxhighlight>procedure TForm1.Panel1Resize(Sender: TObject);
+
<syntaxhighlight lang="pascal">
 +
procedure TForm1.Panel1Resize(Sender: TObject);
 
var  
 
var  
 
   r: TRect;
 
   r: TRect;
Line 522: Line 536:
 
   Panel1.AdjustClientRect(r);
 
   Panel1.AdjustClientRect(r);
 
   ListBox1.Width := (r.Right - r.Left) div 3;
 
   ListBox1.Width := (r.Right - r.Left) div 3;
end;</syntaxhighlight>
+
end;</syntaxhighlight><br /><br />
  
=Custom Controls=
+
=Пользовательские элементы управления=
  
When you write your own control, you can override and fine tune many parts of the LCL autosizing.  
+
Когда вы пишете свой собственный элемент управления, вы можете переопределить и тонко настроить многие части автомасштаба LCL.  
  
 
==SetBounds, ChangeBounds, DoSetBounds==
 
==SetBounds, ChangeBounds, DoSetBounds==
  
'''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.
+
'''SetBounds''' вызывается, когда устанавливаются свойства Left, Top, Width, Height, BoundsRect, или пользователь вызывает его напрямую. SetBounds обновляет BaseBounds и BaseParentClientSize, которые используются [механизмом] привязки для сохранения размеров. Например, загрузка формы с TMemo и lfm[-файлом], содержащим [значения параметров] Left и Width [компонента] TMemo, вызывает [метод] SetBounds для TMemo два раза. Когда пользователь распахивает окно, SetBounds вызывается для формы, но не для Memo, сохраняя BaseBounds Memo. Если Memo привязан справа, [значение параметра] Width [компонента] Memo изменяется на основе [кода методов] BaseBounds и BaseParentClientSize. Имейте в виду, что данные aLeft, aTop, aWidth, aHeight могут быть недействительными и будут изменены LCL перед применением. Delphi чаще всего называет SetBounds. SetBounds вызывает ChangeBounds с KeepBase=false.
  
'''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.
+
'''ChangeBounds''' вызывается всякий раз, когда позиция или размер элемента управления задаются либо с помощью свойств, либо с помощью [механизма разметки] LCL. SetBounds вызывает внутри [себя] ChangeBounds с KeepBase=false, в то время как [механизма разметки] LCL вызывает его с KeepBase=true. Переопределение этого в коде может изменить предпочтительный размер или изменить размеры других элементов управления. Имейте в виду, что данные aLeft, aTop, aWidth, aHeight могут быть недействительными и будут изменены LCL перед применением. Вы можете вызвать эту функцию.
  
'''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.
+
'''DoSetBounds''' - это функция низкого уровня для установки private-переменных FLeft, FTop, FWidth, FHeight. Не вызывайте эту функцию, [потому что] только LCL вызывает ее. Она также обновляет FClientWidth и FClientHeight соответственно. Переопределите ее, чтобы обновить содержимое разметки элемента управления, например полосы прокрутки. Как всегда: не рисуйте здесь, но вызывайте Invalidate и рисуйте в OnPaint или переопределите Paint.
  
'''DoAdjustClientRectChange''' is called by the LCL and the LCL interface, when the ClientRect has changed and the Width and Height were kept.
+
'''DoAdjustClientRectChange''' вызывается LCL и интерфейсом LCL, когда ClientRect изменился, а Width и Height сохранились.
  
'''WMSize''' exists for Delphi/VCL compatibility. It is called by the LCL interface and on every change of bounds.
+
'''WMSize''' существует для совместимости с Delphi/VCL. Он вызывается интерфейсом LCL при каждом изменении границ.
  
 
==AdjustClientRect==
 
==AdjustClientRect==
  
The 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).
+
Метод AdjustClientRect может быть переопределен вашими пользовательскими элементами управления и влияет на [свойства] Align, ChildSizing.Layout и AnchorSides. Это не влияет на значение Left, Top и не влияет на нормальный [механизм] привязки (например, установку).
  
When 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''':
+
Когда вы хотите нарисовать свою собственную рамку, тогда дочерние элементы управления должны быть выровнены в этой рамке. Например, TPanel рисует рамку и уменьшает клиентскую область, переопределяя метод '''AdjustClientRect''':
  
<syntaxhighlight> TCustomPanel = class(TCustomControl)
+
<syntaxhighlight lang="pascal">
 +
  TCustomPanel = class(TCustomControl)
 
   ...
 
   ...
 
   protected
 
   protected
Line 568: Line 583:
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
===AdjustClientRect and Align===
+
===AdjustClientRect и выравнивание===
  
AdjustClientRect 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:
+
AdjustClientRect может использоваться для уменьшения клиентской области, используемой всеми операциями [автоматической установки] размера. Например, TPanel использует AdjustClientRect для уменьшения клиентской области посредством [изменения величины] зазора:
  
 
[[Image:Adjustclientrect_align.png]]
 
[[Image:Adjustclientrect_align.png]]
  
The Button1 in the screenshot was created with Align=alClient. ChildSizing.Layout is affected too.  
+
[Кнопка] Button1 на скриншоте была создана со [значением] Align=alClient. Также [был] задействован [свойство панели] ChildSizing.Layout.
  
When anchoring to a parent via AnchorSides the AdjustClientRect is used too:
+
Когда [дочерний элемент] привязывается к родительскому элементу через [свойство] AnchorSides, также используется параметр AdjustClientRect:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
   Button1.AnchorParallel(akTop,0,Button1.Parent);
 
   Button1.AnchorParallel(akTop,0,Button1.Parent);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The 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).
+
Верхний край Button1 привязан к верхнему краю клиентской области родителя. Если AdjustClientRect добавляет 3px к [значению] Top, Button1.Top будет 3px (3 плюс 0).
  
==Own AutoSize==
+
==Собственный AutoSize==
  
When ''AutoSize'' is set to true the control should be resized to the preferred size if possible.  
+
Когда параметру ''AutoSize'' установлено значение true, элемент управления должен быть изменен до оптимального размера, если это возможно.
  
===Preferred Size===
+
===Предпочтительный размер===
  
The 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:
+
Новый размер выбирается [механизмом] LCL через [метод] '''GetPreferredSize''', который вызывает '''CalculatePreferredSize''' [и] который можно переопределить. Например, давайте опишем '''TQuadrat''', который является [наследником] TShape, но его высота должна быть равна его ширине:
  
<syntaxhighlight> TQuadrat = class(TShape)
+
<syntaxhighlight lang="pascal">
 +
  TQuadrat = class(TShape)
 
   protected
 
   protected
 
     procedure CalculatePreferredSize(var PreferredWidth,
 
     procedure CalculatePreferredSize(var PreferredWidth,
Line 603: Line 620:
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
The 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.
+
Метод CalculatePreferredSize получает два переменных параметра: ''PreferredWidth'' и ''PreferredHeight''. Они по умолчанию равны 0, что означает: нет оптимального размера, поэтому LCL не изменяет размер. Вышеупомянутая функция устанавливает [свойство] ''PreferredHeight'' в текущее [свойство] ''Width''. Логический параметр ''WithThemeSpace'' устарел и всегда [равен] false.
  
'''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.
+
'''Важно''': [метод] CalculatePreferredSize не должен изменять границы или любое другое значение элемента управления, которое может инициировать [механизм] autosize. Это создаст [бесконечный] цикл.
  
Computing 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:
+
Вычисление ''PreferredWidth/Height'' может быть дорогостоящей [операцией]. Поэтому LCL кэширует результат до тех пор, пока для элемента управления не будет вызвана [процедура] ''InvalidatePreferredSize''. В нашем примере ''PreferredHeight'' зависит от [параметра] ''Width'', поэтому мы должны [вызвать] перерисовку [элемента управления], когда изменяется [параметр] ''Width'':
  
<syntaxhighlight> TQuadrat = class(TShape)
+
<syntaxhighlight lang="pascal">
 +
  TQuadrat = class(TShape)
 
   protected
 
   protected
 
     ...
 
     ...
Line 619: Line 637:
 
   inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
 
   inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
 
   InvalidatePreferredSize;
 
   InvalidatePreferredSize;
   // Note: The AdjustSize can be omitted here, because the LCL does that after calling DoSetBounds.
+
   // Примечание: здесь [вызов метода] AdjustSize может быть опущен, поскольку LCL делает это после вызова DoSetBounds.
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
The LCL will automatically trigger the autosizing when the bounds have changed, so the example is complete.
+
LCL автоматически активирует [механизм] autosizing, когда границы изменяются, поэтому пример является полным.
  
The default TWinControl implementation of CalculatePreferredSize queries the widgetset, 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.
+
По умолчанию TWinControl для реализации CalculatePreferredSize запрашивает виджетсет, который может вернуть оптимальную ширину и/или высоту. Каждый элемент управления может переопределять метод CalculatePreferredSize. Например, TImage переопределяет его и возвращает размер изображения. Если нет оптимальной ширины (высоты), возвращаемое значение [будет] равно 0, и LCL будет сохранять текущую [величину] Width (Height). Если 0 - допустимый размер для вашего контроля, вы должны присвоить флагу ControlStyle [значение] csAutoSize0x0 (ControlStyle:=ControlStyle+[csAutoSize0x0];). Примером может служить\элемент управления LCL TPanel.
  
 
===AdjustSize===
 
===AdjustSize===
  
When the preferred size depends on a new property, then every time the property changes the auto sizing must be triggered. For example:
+
Когда предпочтительный размер зависит от нового свойства, то каждый раз, когда свойство изменяется, должен быть вызван [механизм] автоматического изменения размера. Например:
  
<syntaxhighlight>procedure TQuadrat.SetSubTitle(const AValue: string);
+
<syntaxhighlight lang="pascal">
 +
procedure TQuadrat.SetSubTitle(const AValue: string);
 
begin
 
begin
 
   if FSubTitle = AValue then exit;
 
   if FSubTitle = AValue then exit;
Line 636: Line 655:
 
   InvalidatePreferredSize;
 
   InvalidatePreferredSize;
 
   AdjustSize;
 
   AdjustSize;
end;</syntaxhighlight>
+
end;</syntaxhighlight><br /><br />
  
=Reduce overhead with DisableAutoSizing, EnableAutoSizing=
+
=Сокращение накладных расходов с помощью [методов] DisableAutoSizing, EnableAutoSizing=
  
Since 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.
+
Начиная с [версии] Lazarus 0.9.29, существует новый алгоритм автоизменения размера, который уменьшает накладные расходы и допускает глубокие вложенные зависимости. До [версии] 0.9.28 [методы] DisableAlign/EnableAlign и Disable/EnableAutoSize работают только для одного элемента управления и его прямых дочерних контролов.
  
Each time you change a property the LCL triggers a recomputation of the layout:
+
Каждый раз, когда вы меняете [какое-нибудь] свойство, LCL запускает [механизм] пересчета разметки:
  
<syntaxhighlight>Label1.Caption := 'A';  // first recompute
+
<syntaxhighlight lang="pascal">
Label2.Caption := 'B';  // second recompute</syntaxhighlight>
+
Label1.Caption := 'A';  // первый перерасчет
 +
Label2.Caption := 'B';  // второй перерасчет</syntaxhighlight>
  
The recomputations will trigger events and send messages. To reduce the overhead you can suspend the autosizing:
+
Перерасчет будет возбуждать [механизм вызова] событий и отправки сообщений. Чтобы уменьшить накладные расходы, вы можете приостановить [механизм] автоизменения размера:
  
<syntaxhighlight>DisableAutoSizing;
+
<syntaxhighlight lang="pascal">
 +
DisableAutoSizing;
 
try
 
try
   Label1.Caption := 'A';  // no recompute
+
   Label1.Caption := 'A';  // нет перерасчета
   Label2.Caption := 'B';  // no recompute
+
   Label2.Caption := 'B';  // нет перерасчета
 
finally
 
finally
   EnableAutoSizing; // one recompute
+
   EnableAutoSizing; // однократный перерасчет
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
You must balance calls to Disable/EnableAutoSizing. Autosizing starts only when EnableAutoSizing is called after a corresponding (earlier) DisableAutoSizing.
+
Вы должны уравновешивать вызовы Disable/EnableAutoSizing. Автоизменение размера начинается только тогда, когда вызывается EnableAutoSizing после соответствующего (ранее) [вызова] DisableAutoSizing.
  
Since 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:
+
Начиная с [версии Lazarus] 0.9.29, Disable/EnableAutoSize работает для всей формы. Это означает, что каждый вызов DisableAutoSizing приостанавливает автоизменение размера для '''всех''' элементов управления на этой форме. Если вы пишете свой собственный элемент управления, вы можете использовать следующее:
  
<syntaxhighlight>procedure TMyRadioGroup.DoSomething;
+
<syntaxhighlight lang="pascal">
 +
procedure TMyRadioGroup.DoSomething;
 
begin
 
begin
   DisableAutoSizing;  // disables not only TMyRadioGroup, but the whole form's autosizing
+
   DisableAutoSizing;  // отключено автоизменение размера не только [для] TRadioGroup, но и [для] всей формы
 
   try
 
   try
     // delete items ...
+
     // удаляем элементы ...
     // add, reorder items ...
+
     // добавляем, тасуем элементы ...
     // change item captions ...
+
     // меняем заголовки элементов ...
 
   finally
 
   finally
     EnableAutoSizing; // recompute
+
     EnableAutoSizing; // перерасчет
 
   end;
 
   end;
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
Which basically means: you do not have to care. Just call Disable/EnableAutoSizing.  
+
К чему все это: вам не нужно [ни о чем] заботиться. Просто вызовите Disable/EnableAutoSizing.
  
Note: this is wrong:
+
{{Note| вот так неправильно:  
 +
<br /><br />
 +
<syntaxhighlight lang="pascal">
 +
Button1.DisableAutoSizing;
 +
Label1.EnableAutoSizing; // неверно: каждый элемент управления имеет свой собственный
 +
                        //счетчик ссылок на автоизменение размера
 +
</syntaxhighlight>}}
  
<syntaxhighlight>Button1.DisableAutoSizing;
+
==DisableAutoSizing и границы формы==
Label1.EnableAutoSizing; // wrong: every control has its own autosizing reference counter</syntaxhighlight>
 
  
==DisableAutoSizing and Form bounds==
+
DisableAutoSizing имеет еще один полезный эффект при асинхронных менеджерах окон, которые вы [можете] встретить в системах Linux.
 +
Каждый раз, когда форма изменяет размер или перемещается, [ее] границы отправляются в widgetset (DoSendBoundsToInterface). Даже если форма не отображается, дескриптор изменяется. Менеджер окон зачастую рассматривает эти границы только в качестве предложения. У диспетчера окон есть своя логика, и часто используются только границы, переданные первыми. Второе, третье или дальнейшие перемещения могут быть проигнорированы. С помощью параметра DisableAutoSizing вы можете убедиться, что только последние границы отправляются в виджетсет, что делает границы формы более надежными [для отображения].
  
DisableAutoSizing 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 widgetset (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 widgetset making the form bounds more reliable.
 
  
=Example: a button panel=
+
----
 +
[[User:Zoltanleo|Прим.перев.]]: очевидно, имеется ввиду прерывистый механизм перерисовки границ окна, когда при перетаскивании его края мышью рисуется только рамка новой границы окна, а окончательная перерисовка происходит после отпускания кнопки мыши.
 +
----
 +
<br /><br />
  
This 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.
+
=Пример: панель кнопок=
  
Step 1: Create the panel and set its Align property to alBottom. Add three TBitBtns.
+
В этом примере сочетаются несколько механизмов компоновки LCL для создания панели с тремя кнопками: кнопка ''Help'' слева и кнопки ''Ok'' и ''Cancel'' справа. Мы хотим, чтобы панель была внизу формы, заполняя всю [ее] ширину. Кнопки и панель автоматически изменяют размеры, чтобы соответствовать всем шрифтам и темам.
 +
 
 +
Шаг 1: Создайте панель и установите ее свойство Align в alBottom. Добавьте три TBitBtns.
  
 
[[Image:Autosize example buttonpanel1.png]]
 
[[Image:Autosize example buttonpanel1.png]]
  
Set 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.
+
Установите в свойстве ''Kind'' BitBtns [соответственные] отображения глифов. Возможно, вам нужно будет установить свойство GlyphShowMode в gsmAlways[("отображать всегда")], чтобы увидеть их на своей платформе. Установите для свойства ''AutoSize'' [кнопок] BitBtn значение ''True'', которое уменьшит/увеличит [ширину] кнопок для идеального заполнения [их] глифами и текстом. В зависимости от вашей темы и платформы вы можете заметить, что кнопки имеют разную высоту.
  
 
[[Image:Autosize example buttonpanel2.png]]
 
[[Image:Autosize example buttonpanel2.png]]
  
Set 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.
+
Установите свойство ''Align ' кнопки справки в ''alLeft'' и установите для остальных двух кнопок свойство ''Align'' в ''alRight''. Это увеличит кнопки по вертикали и переместит их в крайнее левое/правое. alLeft/alRight не влияют на ширину, поэтому кнопки используют свою предпочтительную ширину.
  
 
[[Image:Autosize example buttonpanel3.png]]
 
[[Image:Autosize example buttonpanel3.png]]
  
The Panel height is still fixed. Now set the panel ''AutoSize'' property to ''True''. The panel now shrinks vertically to fit the tallest button.
+
Высота панели по-прежнему фиксирована. Теперь установите для панели свойство ''AutoSize'' в ''True''. Панель теперь сжимается вертикально, чтобы соответствовать самой высокой кнопке.
  
 
[[Image:Autosize example buttonpanel4.png]]
 
[[Image:Autosize example buttonpanel4.png]]
  
The ''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.
+
Кнопка ''Ok'' имеет короткий заголовок, поэтому кнопка очень маленькая. Установите для кнопки ''Constraints.MinWidth'' в значение ''75''. Теперь кнопка несколько расширится.
  
 
[[Image:Autosize example buttonpanel5.png]]
 
[[Image:Autosize example buttonpanel5.png]]
  
Now add some space around the buttons. Set the panel's ''ChildSizing.LeftTopSpacing/RightBottomSpacing/HorizontalSpacing'' to ''6''.
+
Теперь добавьте некоторое пространство вокруг кнопок. Установите для панели ''ChildSizing.LeftTopSpacing/RightBottomSpacing/HorizontalSpacing'' в значение ''6''.
  
 
[[Image:Autosize example buttonpanel6.png]]
 
[[Image:Autosize example buttonpanel6.png]]
  
Finally clear the ''Caption'' of the panel and set its ''BevelOuter'' to ''bvNone''.
+
Наконец, очистите ''Caption'' панели и установите ее 'BevelOuter'' в ''bvNone''.
  
 
[[Image:Autosize example buttonpanel7.png]]
 
[[Image:Autosize example buttonpanel7.png]]
 +
<br /><br />
  
=Scrolling=
+
=Прокрутка=
  
Some 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'''.
+
Некоторые элементы управления LCL, такие как ''TScrollBox'', ''TForm' и ''TFrame'', показывают полосы прокрутки, если дочерние элементы управления слишком велики, чтобы поместиться на scrollbox, форме или фрейме. Они наследуют это поведение от своего предка '''TScrollingWinControl'''.
  
A 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:
+
Прокручиваемая '''логическая клиентская область''' элемента управления может быть больше, чем '''видимая клиентская область'''. '''Видимая клиентская область''' - это '''ClientRect'''. Она всегда начинается с [координат] 0,0 и его ширина и высота - это внутренняя область. Например, в TGroupBox - это размер области внутри фрейма. Итак, всегда верно следующее:
  
<syntaxhighlight>ClientWidth <= Width
+
<syntaxhighlight lang="pascal">
 +
ClientWidth <= Width
 
ClientHeight <= Height</syntaxhighlight>
 
ClientHeight <= Height</syntaxhighlight>
  
The '''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'':
+
'''Логическая клиентская область''' определяется методом '''GetLogicalClientRect'''. По умолчанию она совпадает с ''ClientRect''. Когда дочерний элемент управления привязан к правой стороне, он использует ''логическую клиентская область''. ''TScrollingWinControl'' переопределяет этот метод и возвращает ''Range''[(диапазон)] полос прокрутки, если [логическая клиентская область] больше, чем ''ClientRect''. '''Range''' можно установить вручную или автоматически с помощью ''AutoScroll=true''. Пример для ''AutoScroll=true'':
  
 
[[Image:Autoscroll all fit1.png]]
 
[[Image:Autoscroll all fit1.png]]
  
The 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.  
+
Верхняя кнопка имеет фиксированную ширину 200. Нижняя кнопка привязана к правой стороне панели. Поэтому дочерние элементы управления имеют предпочтительную ширину 200. Поскольку панель больше 200, логическая область клиента больше и нижняя кнопка расширяется.
  
Now the panel is shrunk, so that the ClientWidth becomes lower than 200:
+
Теперь панель сжата, так что ClientWidth становится меньше 200:
  
 
[[Image:Autoscroll not fit1.png]]
 
[[Image:Autoscroll not fit1.png]]
  
The 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.
+
Предпочтительная ширина по-прежнему равна 200, поэтому логического клиентская область теперь равна 200 и больше, чем видимая клиентская область. Нижняя кнопка имеет ширину 200, а на панели отображается горизонтальная полоса прокрутки.
  
==Scroll Position==
+
==Позиция прокрутки==
  
Changing 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.
+
Изменение положения полосы прокрутки не изменяет [значения] Left или Top любого дочернего элемента управления и не изменяет логическую клиентскую область, [а также] не влияет на автомасштабирование. Дочерние элементы управления лишь только виртуально перемещаются.
  
==Scrolling and AutoSize==
+
==Прокрутка и автомасштаб==
  
When 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.
+
Когда AutoSize=true, LCL расширяет [родительский] элемент управления [так], чтобы разместить все его дочерние элементы управления, и никаких полос прокрутки не требуется. Если [родительский] элемент управления не может быть расширен, то (только) [тогда проявляется] вторичное действие AutoSize: перемещение дочерних элементов управления.
  
=Docking=
+
=Пристыковка=
  
Docking uses the described methods and properties of this page, see [[Docking]].
+
Пристыковка использует описанные методы и свойства этой страницы, см. [[Docking]].
  
 
=Splitter=
 
=Splitter=
  
See [[TSplitter]].
+
См. [[TSplitter/ru|TSplitter]].
  
 
=TLabel.WordWrap=
 
=TLabel.WordWrap=
  
'''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.
+
'''TLabel.WordWrap'''[(перенос слов)] изменяет поведение предпочтительного размера [компонента] label. '''WordWrap=true''' требует, чтобы [величина] Width [компонента] label была фиксированной, например, путем привязки левого и правого размера [компонента] label. Предпочтительная высота label затем вычисляется путем разбиения [своства] Caption на несколько строк.
  
=DPI auto-adjustment and absolute layout auto-adjustment=
+
=Автоматическая настройка DPI и автоматическая настройка статической разметки=
  
Historically 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 ok, but with the advent of LCL support for Android this could no longer be ignored. Starts 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.
+
Исторически LCL использовался в основном для создания статической разметки, несмотря на огромное количество опций, которые Lazarus предлагает для гибкой разметки макетов, таких как Align, Anchors и т.д., которые описаны в остальной части этой статьи. Кроме того, он также исторически игнорировал DPI целевого [рабочего стола] и вместо этого использовал значения в пикселях для измерения свойств слева, сверху, ширины и высоты элементов управления. Для настольных платформ и Windows CE это работает нормально, но с появлением поддержки LCL для Android это больше нельзя игнорировать. Начиная с Lazarus 0.9.31, LCL может пересчитывать статическую разметку LCL в пикселях [на разметку] в виде гибкой сетки. Существует выбор нескольких режимов, [которые] позволяют пересчитывать значения пикселей как в абсолютных [величинах], так и в корректируемых для DPI, или как считающихся просто частью размера формы.
  
It is important to note that these new rules affect only controls which are positioned without Align and with the most standard Anchors only.
+
Важно отметить, что эти новые правила влияют только на элементы управления, которые расположены без выравнивания и только с большинством стандартных привязок.
  
In 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 positoning values will be expanded when the target DPI is larger then the design time DPI or reduced otherwise. The common value for desktop DPIs is 96 and is the default value given.
+
В случае, когда значения будут корректироваться для DPI, появляется новое свойство: TCustomForm.DesignTimeDPI, которое должно хранить значение DPI системы, в которой была создана форма. Значения позиционирования будут расширены, когда DPI целевого [рабочего стола] будет больше, чем время DPI времени разработки или уменьшено в противном случае. Обычное значение DPI для рабочего стола - 96, и это значение, заданное по умолчанию.
  
property DesignTimeDPI: Integer read FDesignTimeDPI write FDesignTimeDPI;
+
<tt>property DesignTimeDPI: Integer read FDesignTimeDPI write FDesignTimeDPI;</tt>
  
The way in which the layout is adjusted can be controlled with the property TApplication.LayoutAdjustmentPolicy
+
Способ настройки разметки можно контролировать с помощью свойства TApplication.LayoutAdjustmentPolicy
  
 +
<syntaxhighlight lang="pascal">
 
   TLayoutAdjustmentPolicy = (
 
   TLayoutAdjustmentPolicy = (
     lapDefault,    // widgetset dependent
+
     lapDefault,    // Зависимость от виджетсета
     lapFixedLayout, // A fixed absolute layout in all platforms
+
     lapFixedLayout, // Фиксированная абсолютная разметка на всех платформах
     lapAutoAdjustWithoutHorizontalScrolling, // Smartphone platforms use this one,
+
     lapAutoAdjustWithoutHorizontalScrolling, // Это используется платформой для смартфонов,
                                             // the x axis is stretched to fill the screen and
+
                                             // ось x растягивается, чтобы заполнить экран и
                                             // the y is scaled to fit the DPI
+
                                             // y масштабируется, чтобы соответствовать DPI
     lapAutoAdjustForDPI // For desktops using High DPI, scale x and y to fit the DPI
+
     lapAutoAdjustForDPI // Для рабочих столов с использованием High DPI, x и y масштабируются соответственно DPI
   );
+
   );</syntaxhighlight>
  
And 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 descendents of TControl react to this:
+
Следующие новые методы в TControl позволяют [задать] принудительную автонастройку разметки в конкретном контроле и во всех его дочерних элементах, или контролировать, как реагируют на это отдельные потомки TControl:
  
<syntaxhighlight>
+
<syntaxhighlight lang="pascal">
 
TControl = class
 
TControl = class
 
public
 
public
Line 791: Line 825:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
LCL-CustomDrawn-Android will call AutoAdjustLayout when the screen rotates, for example.
+
LCL-CustomDrawn-Android будет вызывать AutoAdjustLayout, например, когда экран вращается.<br /><br />
  
=More details=
+
=Подробнее=
  
     <p>Many controls override ''TControl.DoAutoSize'' to perform the actual auto-sizing. </p>
+
     <p>Многие элементы управления переопределяют ''TControl.DoAutoSize'' для выполнения фактического автомасштабирования. </p>
     <p>IMPORTANT: Many Delphi controls override this method and many call this method directly after setting some properties.</p>
+
     <p>ВАЖНО: Многие элементы управления Delphi переопределяют этот метод, и многие вызывают этот метод напрямую после установки некоторых свойств.</p>
     <p>During handle creation not all interfaces can create complete Device Contexts which are needed to calculate things like text size.</p>
+
     <p>Во время создания дескриптора не все интерфейсы могут создавать полные Device Contexts[(контексты устройств)], которые необходимы для вычисления таких вещей, как размер текста.</p>
           <p>That's why you should always call ''AdjustSize'' instead of <var>DoAutoSize</var>.</p>
+
           <p>Вот почему вы всегда должны называть ''AdjustSize'' вместо <var>DoAutoSize</var>.</p>
 
   
 
   
  <p><var>TControl.AdjustSize</var> calls <var>DoAutoSize</var> in a smart fashion.</p>
+
  <p><var>TControl.AdjustSize</var> вызывает <var>DoAutoSize</var> умным способом.</p>
  <p>During loading and handle creation the calls are delayed.</p>
+
  <p>Во время загрузки и создания дескриптора вызовы задерживаются.</p>
           <p>This method initially does the same as ''TWinControl.DoAutoSize''.  But since <var>DoAutoSize</var> 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 <var>AdjustSize</var> instead.</p>
+
           <p>Этот метод изначально делает то же самое, что и ''TWinControl.DoAutoSize''. Но поскольку <var>DoAutoSize</var> обычно переопределяется компонентами-потомками, нецелесообразно выполнять все проверки, которые могут привести к слишком большим издержкам. Чтобы уменьшить это, LCL вызывает <var>AdjustSize</var>.</p>
  
When 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:
+
При установке AutoSize=true LCL автомасштабирует элемент управления по ширине и высоте. Это одна из самых сложных частей LCL, потому что результат зависит от почти сотен свойств. Начнем с простого:
  
The LCL will only autosize the ''Width'' (Height) if it is free to resize. In other words - the width is not autosized if:
+
LCL будет только автомасштабировать ''Width'' (Height), если [это свойство] свободно для изменения величины. Другими словами - ширина не автомасштабируется, если:
*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.
+
*левая и правая стороны привязаны. Вы можете привязать стороны с [помощью] свойства '''Anchors''' или установить свойство ''Align'' в alTop, alBottom или alClient.
*the ''Width'' is bound by the ''Constraints'' properties. The Contraints can also be overriden by the widgetset. For example the winapi does not allow resizing the height of a combobox. And the gtk widgetset does not allow resizing the width of a vertical scrollbar.
+
*[параметр] ''Width'' ограничен [значением] свойства ''Constraints''. [Свойство] Constraints также может быть переопределено виджетсетом. Например, winapi не позволяет изменять размер выпадающего списка. Или gtk widgetset не позволяет изменять ширину вертикальной полосы прокрутки.
  
Same for ''Height''.
+
То же [справедливо и для свойства] ''Height''.
  
The new size is calculated by the protected method '''TControl.CalculatePreferredSize'''.
+
Новый размер рассчитывается protected-методом '''TControl.CalculatePreferredSize'''.
This method asks the widgetset 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.
+
Этот метод запрашивает виджетсет для [получения] подходящих Width и Height. Например, TButton имеет предпочтительные ширину и высоту. TComboBox имеет только предпочтительную высоту. [У него] предпочтительная ширина возвращается как 0, и поэтому LCL не автомасштабирует ширину - [LCL] сохраняет ширину неизменной. Наконец, у TMemo нет предпочтительной ширины или высоты. Поэтому [параметр] AutoSize не влияет на TMemo.
  
Some controls override this method. For example the TGraphicControl descendants like TLabel have no window handle and so cannot query the widgetset. They must calculate their preferred Width and Height themselves.
+
Некоторые элементы управления перекрывают этот метод. Например, потомки TGraphicControl, такие как TLabel, не имеют дескриптора окна и поэтому не могут запрашивать виджетсет. Они должны сами рассчитать их предпочтительную ширину и высоту.
  
The widgetsets must override the GetPreferredSize method for each widget class that has a preferred size (Width or Height or both).
+
Виджетсеты должны переопределять метод GetPreferredSize для каждого класса виджетов, который имеет предпочтительный размер (ширина или высота, или оба).
  
 
==Parent.AutoSize==
 
==Parent.AutoSize==
  
The above described the simple explanation. The real algorithm provides far more possibilities and is therefore far more complex.
+
Выше описанное [дает] простое объяснение. Реальный алгоритм [функционально] предусматривает гораздо больше возможностей и, следовательно, гораздо более сложен.
  
==Properties / Methods==
+
==Свойства / Методы==
  
*Left
+
*<tt>Left</tt>
*Top
+
*<tt>Top</tt>
  
If 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 widgetsets define a minimum/maximum somewhere around 10.000 or more.
+
Если Parent<>nil, то [значения] Left, Top - это расстояние в пикселях до верхнего левого пикселя клиентской области родителя (не прокручивается). Помните, что клиентская область - это всегда [область] ''без'' рамки и полосы прокрутки родителя. Для пользователей Delphi: некоторые элементы управления VCL, такие как TGroupbox, определяют клиентскую область как весь элемент управления, включая рамку, а некоторые нет - LCL же более последователен, поэтому Delphi [с ним] несовместим. Left и Top могут иметь отрицательные [значения] или [быть] больше, чем область клиента. Некоторые виджетсеты определяют минимум/максимум где-то около 10000[px] или более.
  
When the client area is scrolled the Left and Top are kept unchanged.  
+
Когда клиентская область прокручивается, Left и Top остаются неизменными.
  
During resizing/moving Left and Top are not always in sync with the coordinates of the Handle object.
+
Во время изменения размера/перемещения [элемента управления] Left и Top не всегда синхронизируются с координатами дескриптора объекта.
  
If Parent=nil then Left, Top depend on the widgetset 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.
+
Если Parent=nil, тогда [значения] Left, Top зависят от виджетсета и диспетчера окон. До [версии] Lazarus 0.9.25 это обычно были координаты экрана верхне-левой части клиентской области формы. Это несовместимо с Delphi. Планируется изменить это [поведение] на Left, Top окна.
  
 +
Подсказка:
 +
Каждый раз, когда вы изменяете Left и Top, LCL мгновенно приходит в движение и перекомпонует весь макет. Если вы хотите изменить Left ''и'' Top, используйте взамен:
  
Hint:
+
<syntaxhighlight lang="pascal">
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:
+
with Button1 do
<syntaxhighlight>with Button1 do
 
 
   SetBounds(NewLeft, NewTop, Width, Height);</syntaxhighlight>
 
   SetBounds(NewLeft, NewTop, Width, Height);</syntaxhighlight>
 +
<br />
  
*Width
+
*<tt>Width</tt>
*Height
+
*<tt>Height</tt>
  
The Size in pixels must not be negative, and most widgetsets 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.
+
Размер в пикселях не должен быть отрицательным, и большинство виджетсетов не допускают Width=0 и/или Height=0. Некоторые элементы управления на некоторых платформах определяют наибольшее минимальное ограничение в Constraints.MinInterfaceWidth/Height. Вместо того, чтобы изменять размер элемента управления в Width=0 и/или Height=0, установите Visible=false или Parent=nil. Во время изменения размера/перемещения [свойства] Width и Height не всегда синхронизируются с размером дескриптора объекта.
 +
<br />
  
 +
*<tt>BoundsRect</tt>
  
*BoundsRect
+
Аналогично <tt>Bounds(Left, Top, Width, Height)</tt>.
  
Same as Bounds(Left, Top, Width, Height).
+
Обычная ошибка новичка:
  
Common newbie mistake:
+
<syntaxhighlight lang="pascal">
<syntaxhighlight>BoundsRect.Left := 3; // WRONG: common newbie mistake</syntaxhighlight>
+
BoundsRect.Left := 3; // НЕПРАВИЛЬНО: обычная ошибка новичка</syntaxhighlight><br />
This has no effect, because reading BoundsRect is a function. It creates a temporary TRect on the stack. The above is the same as
+
Это не [оказывает никакого] влияния, потому что чтение BoundsRect является функцией. Она создает временный TRect в стеке. Вышеупомянутое те же, что и
<syntaxhighlight>var
+
 
 +
<syntaxhighlight lang="pascal">
 +
var
 
   r: TRect;
 
   r: TRect;
 
begin
 
begin
   r := BoundsRect; // fetch the bounds
+
   r := BoundsRect; // получаем границы
   r.Left := 3;  // change a value on the stack
+
   r.Left := 3;  // изменяем значение в стеке
end;  // no change</syntaxhighlight>
+
end;  // нет изменений</syntaxhighlight>
 
+
<br />
*ClientRect
 
 
 
Left 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.
 
 
 
*ClientOrigin
 
 
 
Returns 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.
 
 
 
*LCLIntf.GetClientBounds
 
 
 
Returns 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.
 
 
 
*LCLIntf.GetWindowRect
 
 
 
After 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.
 
 
 
 
 
*FBaseBoundsLock: integer
 
  
Increased/Decreased by LockBaseBounds/UnlockBaseBounds.
+
*<tt>ClientRect</tt>
Used to keep FBaseBounds during SetBounds calls.
 
  
 +
Left и Top всегда равны 0,0. [Свойства] Width и Height - это видимый размер клиентской области в пикселях. Помните, что клиентская область - это [то, что] без рамки и без полос прокрутки. В прокручиваемой клиентской области логическая клиентская область может быть больше видимой.
 +
<br />
  
*FBaseParentClientSize: TPoint
+
*<tt>ClientOrigin</tt>
  
The Parent.ClientRect size valid for the FBaseBounds.
+
Возвращает экранную позицию верхне-левой координаты 0,0 клиентской области. Обратите внимание, что это значение является позицией, сохраненной в интерфейсе, и не всегда синхронизируется с LCL. Когда элемент управления перемещается, LCL устанавливает границы в нужную позицию и отправляет сообщение [о] перемещении в интерфейс. Интерфейс обрабатывает [сообщения о] перемещениях сразу или по очереди.
FBaseBounds and FBaseParentClientSize are used to calculate the distance for
+
<br />
akRight (akBottom). When the parent is resized, the LCL knows what distance to keep.
 
  
 +
*<tt>LCLIntf.GetClientBounds</tt>
  
*FBoundsRectForNewParent: TRect
+
Возвращает клиентские границы элемента управления. Аналогичен ClientRect, но Left и Top - это расстояния в пикселах до левого и верхнего краев элемента управления. Например, в TGroupBox [параметры] Left, Top являются шириной и высотой левой и верхней границ рамки. Прокрутка не влияет на GetClientBounds.
 +
<br />
  
When changing the Parent of a control the Handle is recreated and many
+
*<tt>LCLIntf.GetWindowRect</tt>
things can happen. Especially for docking forms the process is too
 
unreliable. Therefore the BoundsRect is saved. The VCL uses a similar
 
mechanism.
 
  
 +
После вызова [этой функции] ARect будет областью элемента управления в координатах экрана. Это означает, что Left и Top будут экранной координатой верхне-левого пикселя Дескриптора объекта, а [значения] Right и Bottom будут экранной координатой нижне-правого пиксела.
 +
<br />
  
*fLastAlignedBounds: TRect
+
*<tt>FBaseBoundsLock: integer</tt>
  
See TControl.SetAlignedBounds for an explanation.
+
Увеличивается/уменьшается [методами] LockBaseBounds/UnlockBaseBounds.
In short: It stops some circles between interface and LCL autosizing.
+
Используется для сохранения [поля] FBaseBounds во время вызова SetBounds.
 +
<br />
  
 +
*<tt>FBaseParentClientSize: TPoint</tt>
  
*FLastChangebounds: TRect
+
Размер Parent.ClientRect действителен для FBaseBounds.
 +
[Поля] FBaseBounds и FBaseParentClientSize используются для вычисления расстояния для [параметра выравнивания]
 +
akRight (aBBottom). Когда размер родителя изменяется, LCL знает, какое расстояние сохранить.
 +
<br />
  
Used to stop calling ChangeBounds with the same coordinates. This happens
+
*<tt>FBoundsRectForNewParent: TRect</tt>
very often.
 
  
 +
При смене родителя элемента управления Дескриптор [объекта] создается [заново], и многое
 +
может случиться. Особенно этот процесс ненадежен для пристыкованных форм. Поэтому BoundsRect сохраняется. VCL использует аналогичные механизм.
 +
<br />
  
*FLastDoChangeBounds: TRect
+
*<tt>fLastAlignedBounds: TRect</tt>
  
Used to avoid calling OnChangeBounds with the same coordinates. This reduces
+
Для получения пояснения см. <tt>TControl.SetAlignedBounds</tt>.
user defined autosizing.
+
Коротко: он останавливает некоторые циклы между интерфейсом и автомасштабированием в LCL.
 +
<br />
  
 +
*<tt>FLastChangebounds: TRect</tt>
  
*FLastResizeClientHeight: integer
+
Используется для остановки вызова ChangeBounds с одинаковыми координатами. Это случается очень часто.
*FLastResizeClientWidth: integer
+
<br />
*FLastResizeHeight: integer
 
*FLastResizeWidth: integer
 
  
Used to avoid calling OnResize with the same coordinates. This reduces user
+
*<tt>FLastDoChangeBounds: TRect</tt>
defined autosizing.
 
  
 +
Используется, чтобы избежать вызова OnChangeBounds с теми же координатами. Это подавляет пользовательскую настройку автомасштабирования.
 +
<br />
  
*FLoadedClientSize: TPoint
+
*<tt>FLastResizeClientHeight: integer</tt>
 +
*<tt>FLastResizeClientWidth: integer</tt>
 +
*<tt>FLastResizeHeight: integer</tt>
 +
*<tt>FLastResizeWidth: integer</tt>
  
During loading many things are delayed and many things are set and worse: in
+
Используется, чтобы избежать вызова OnResize с теми же координатами. Это подавляет пользовательскую настройку автомасштабирования.
the wrong order. That's why SetClientWidth/SetClientHeight calls are stored
+
<br />
and set at end of loading again.
 
This way the LCL can restore the distances (e.g. akRight) used during
 
designing.
 
  
 +
*<tt>FLoadedClientSize: TPoint</tt>
  
*FReadBounds: TRect
+
Во время загрузки многие вещи задерживаются, а многие вещи устанавливаются в неправильном порядке и ухудшаются. Вот почему  сохраняется и вновь вызывается ''SetClientWidth/SetClientHeight'' в конце загрузки.
 +
Таким образом, LCL может восстанавливать размеры (напр., при ''akRight''), используемые во время проектирование.
 +
<br />
  
Same as FLoadedClientSize, but for SetLeft, SetTop, SetWidth, SetHeight.
+
*<tt>FReadBounds: TRect</tt>
  
 +
Аналогично <tt>FLoadedClientSiz</tt>, но для <tt>SetLeft</tt>, <tt>SetTop</tt>, <tt>SetWidth</tt>, <tt>SetHeight</tt>.
 +
<br />
 
   
 
   
*procedure SetBoundsRectForNewParent(const AValue: TRect);
+
*<tt>procedure SetBoundsRectForNewParent(const AValue: TRect);</tt>
  
Used to set FBoundsRectForNewParent. See above.
+
Используется для установки <tt>FBoundsRectForNewParent</tt>. См. выше.
 +
<br />
  
 +
*<tt>procedure SetAlignedBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;</tt>
  
*procedure SetAlignedBounds(aLeft, aTop, aWidth, aHeight: integer); virtual; 
+
Как SetBounds, но без изменения размеров по умолчанию.
 +
<br />
  
As SetBounds but without changing the default sizes.
+
*<tt>procedure SetInitialBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;<//tt> 
  
 +
"Умная" версия SetBounds, уменьшающая накладные расходы при создании и загрузке.
 +
<br />
  
*procedure SetInitialBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
+
*<tt>procedure UpdateBaseBounds(StoreBounds, StoreParentClientSize, UseLoadedValues: boolean); virtual;</tt>
  
A smart version of SetBounds, reducing overhead during creation and loading.
+
Фиксирует текущие границы базовых границ.
 +
<br />
  
 +
*<tt>procedure SetClientHeight(Value: Integer);</tt>
 +
*<tt>procedure SetClientSize(Value: TPoint);</tt>
 +
*<tt>procedure SetClientWidth(Value: Integer);</tt> 
  
*procedure UpdateBaseBounds(StoreBounds, StoreParentClientSize, UseLoadedValues: boolean); virtual;
+
Существует также для совместимости с Delphi. Изменяет размер элемента управления, чтобы получить желаемый размер ClientRect.
 +
<br />
  
Commit current bounds to base bounds.
+
*<tt>procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;</tt>
  
*procedure SetClientHeight(Value: Integer);
+
Это внутренний SetBounds.
*procedure SetClientSize(Value: TPoint);
+
Применяет ограничения, обновляет базовые границы, вызывает OnChangeBound, OnResize, блокирует границы.
*procedure SetClientWidth(Value: Integer); 
+
<br />
  
Exists for Delphi compatibility too. Resizes the control, to get the wanted ClientRect size.
+
*<tt>procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;</tt>
  
 +
Этот [метод] действительно устанавливает частные private-переменные FLeft, FTop, FWidth, FHeight.
 +
<br />
  
*procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
+
*<tt>procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;</tt>
  
This is the internal SetBounds.
+
Это стандартная процедура, переопределяющая многие элементы управления Delphi. Также переопределяет TWinControl.
Applies constraints, updates base bounds, calls OnChangeBound, OnResize,
+
** игнорирует вызовы, когда границы заблокированы
locks bounds.
+
** блокирует FBoundsRealized, чтобы избежать накладных расходов на интерфейс во время автомасштабирования. ChangeBounds таким образом не блокируется.<br />
  
 +
*<tt>Function GetClientOrigin: TPoint; virtual;</tt>
  
*procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;
+
Координаты экрана Left, Top клиентской области.
 +
<br />
  
This really sets the FLeft, FTop, FWidth, FHeight private variables.
+
*<tt>Function GetClientRect: TRect; virtual;</tt>
  
 +
Размер клиентской области. (всегда Left=0, Top=0)
 +
<br />
  
*procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;
+
*<tt>Function GetScrolledClientRect: TRect; virtual;</tt>
  
This is the standard procedure overriden by many Delphi controls.
+
Видимая клиентская область ClientRect.
TWinControl overrides it too.
+
<br />
** ignores calls when bounds are locked
 
** lock the FBoundsRealized to avoid overhead to the interface during auto sizing.
 
ChangeBounds is not locked this way.
 
  
+
*<tt>function GetChildsRect(Scrolled: boolean): TRect; virtual;</tt>
*Function GetClientOrigin: TPoint; virtual;
 
  
Screen coordinate of Left, Top of client area.
+
Возвращает клиентский прямоугольник относительно Left, Top элемента управления.
 +
Если [свойство] Scrolled [имеет значение] true, прямоугольник перемещается текущими значениями прокрутки (например, см. TScrollingWincontrol).
 +
<br />
  
*Function GetClientRect: TRect; virtual;
+
*<tt>function GetClientScrollOffset: TPoint; virtual;</tt>
  
Size of client area. (always Left=0, Top=0)
+
Возвращает смещение прокрутки клиентской области.
 +
<br />
  
*Function GetScrolledClientRect: TRect; virtual;
+
*<tt>function GetControlOrigin: TPoint; virtual;</tt>
  
Visible client area in ClientRect.
+
Возвращает экранные координаты верхне-левой координаты 0,0 области элемента управления (верхне-левый пиксель элемента управления на экране).
 +
Обратите внимание, что это значение является позицией, сохраненной в интерфейсе, и не всегда синхронизируется с LCL. Когда элемент управления перемещается, LCL устанавливает границы в желаемую позицию и отправляет сообщение о перемещении в интерфейс. [А уж] интерфейс обрабатывает перемещаемый дескриптер сразу или в [порядке] очереди.
 +
<br />
 +
<br />
  
 +
=ЧаВо=
  
*function GetChildsRect(Scrolled: boolean): TRect; virtual;
+
==Почему [свойство] AutoSize не работает в дизайнере должным образом?==
  
Returns the Client rectangle relative to the control's Left, Top.
+
В дизайнере элементы управления можно перемещать, и свойства могут быть установлены практически в любом порядке. Чтобы разрешать это и избегать возможных конфликтов, [свойство] AutoSizing не обновляется при каждом изменении во время разработки.
If Scrolled is true, the rectangle is moved by the current scrolling values
 
(for an example see TScrollingWincontrol).
 
  
*function GetClientScrollOffset: TPoint; virtual;
+
==Почему TForm.AutoSize не работает, когда что-то меняется?==
  
Returns the scrolling offset of the client area.
+
См. [[Autosize_/_Layout/ru#Автомасштаб и формы|Автомасштаб и формы]]
  
 +
==Нужно ли мне вызывать Application.ProcessMessages при создании большого количества элементов управления?==
  
*function GetControlOrigin: TPoint; virtual;
+
Application.ProcessMessages вызывается LCL автоматически после каждого сообщения (например, после каждого события, такого как OnClick). Вызов его сам по себе необходим только в том случае, если изменения должны немедленно стать видимыми пользователю. Например:
  
Returns the screen coordinate of the topleft coordinate 0,0 of the control area. (The topleft pixel of the control on the screen)
+
<syntaxhighlight lang="pascal">
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
+
procedure TFrom.Button1Click(Sender: TObject);
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.
 
 
 
=FAQ=
 
 
 
==Why does AutoSize not work in the designer properly?==
 
 
 
In 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.
 
 
 
==Why does TForm.AutoSize not work when something changes?==
 
 
 
See [[Autosize_/_Layout#AutoSize_and_Forms|AutoSize and Forms]]
 
 
 
==Do I need to call Application.ProcessMessages when creating lots of controls?==
 
 
 
Application.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:
 
 
 
<DELPHI>procedure TFrom.Button1Click(Sender: TObject);
 
 
begin
 
begin
   // change width of a control
+
   // изменяем ширину элемента управления
 
   Button1.Width := Button1.Width + 10;
 
   Button1.Width := Button1.Width + 10;
   // apply any needed changes and repaint the button
+
   // применяем все необходимые изменения и перерисовываем кнопку
 
   Application.ProcessMessages;
 
   Application.ProcessMessages;
   // do a lot of things that takes a long time
+
   // делаем много вещей, которые занимают много времени
 
   ...
 
   ...
   // after leaving the OnClick the LCL automatically processes messages
+
   // после выхода из OnClick LCL автоматически обрабатывает сообщения
end;</DELPHI>
+
end;</syntaxhighlight>
 +
 
 +
==При включении привязки во время исполнения [приложения] элементы управления изменяют размеры, но не используют текущие значения. Почему?==
  
==When enabling Anchors at runtime the control resizes, does not use the current values. Why?==
+
akBottom означает: сохранить расстояние до нижней части родителя.
 +
Зазоры для удержания определяются основными границами. Они устанавливаются в режиме разработки или во время исполнения вызовом [методов] SetBounds или UpdateBaseBounds.
  
akBottom 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.
+
TListBox (Anchors=[akLeft,aTop]) при проектировании имеет нижний зазор в 100 пикселей.
 +
И кнопку для включения/выключения [значения] akBottom TListBox'а.
 +
Теперь запустите приложение и нажмите кнопку, чтобы включить akBottom. 100-пиксельное расстояние будет активировано, потому что это был последний раз, когда программист определил базовые границы TListBox. Все остальные изменения были сделаны LCL и не имеют значения. Основные границы[, заданные] программистом определяют правила. Вы можете изменить размер формы, но 100 пикселей будет сохранено.
 +
Чтобы использовать текущие границы в качестве базовых, используйте:
  
For example:
+
<syntaxhighlight lang="pascal">
A TListBox (Anchors=[akLeft,aTop]) at designtime has a bottom distance of 100 pixel.
+
ListBox1.UpdateBaseBounds(true, true, false);
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:
 
<syntaxhighlight>ListBox1.UpdateBaseBounds(true, true, false);
 
 
ListBox1.Anchors := ListBox1.Anchors + [akBottom];</syntaxhighlight>
 
ListBox1.Anchors := ListBox1.Anchors + [akBottom];</syntaxhighlight>
  
Setting Anchors does not automatically call UpdateBaseBounds, because this would destroy the ability to change properties independently.
+
Установка привязки не вызывает автоматически [вызов метода] UpdateBaseBounds, потому что это само по себе может уничтожить возможность изменения свойств.
  
==Resizing stringgrid columns in form's OnResize event does not work==
+
==Изменение размера столбцов stringgrid в событии OnResize формы не работает==
  
The Form's OnResize is triggered when the Form's Width, Height, ClientWidth or ClientHeight changes.
+
[Событие] OnResize формы запускается, когда изменяются [значения] Width, Height, ClientWidth или ClientHeight формы. Это само по себе не зависит [непосредственно] от TStringGrid. Конечно, часто бывает, что и форма, и TStringGrid изменяют размеры. Это означает[, что в таких случаях] использование [события] OnResize формы часто будет работать, но не всегда. Ярким примером [того, что использование OnResize формы] всегда терпит неудачу, является [случай], когда тема изменена, и у вас есть TStringGrid[, лежащий] в TGroupBox на TForm. Когда тема меняется, размеры формы сохраняются, поэтому никакого [события] OnResize формы не запускается. Но меняется [соответственно теме] TGroupBox, поэтому TStringGrid должен быть изменен.
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.
 
  
Solution: Use the TStringGrid's OnResize.
+
Решение: используйте [событие] OnResize TStringGrid'а.
  
==Why is TForm.Width equal to TForm.ClientWidth?==
+
== Почему TForm.Width равен TForm.ClientWidth?==
  
Mattias' notes:
+
Примечание Mattias'а:
  
"There are historical and technical reasons.
+
"Есть исторические и технические причины.
  
For 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.
+
Для форм без родителя Clientwidth равен Width, поскольку реальная ширина, включая рамку, не была доступна в Linux десять лет назад (по крайней мере, не достоверно для разных оконных менеджеров). Я не тестировал, но слышал, что теперь это возможно с gtk2. Основная проблема заключается в автомасштабировании, потому что для этого нужны размеры рамки до того, как форма будет отображена на экране. Возможно, [размер рамки] доступен только после [наступления] события, а это значит, что вам нужно подождать, что означает проблему для ShowModal.
Changing this breaks compatibility with a lot of existing LCL code, but for this we added the LCLVersion in the lfm files.
+
Изменив это, вы нарушите совместимость с большим количеством существующего кода [[LCL/ru]], но для этого мы добавили LCLVersion в файлы lfm.
  
For 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."
+
Существует новое определение компилятора '''LCLRealFormBounds''' в Lazarus trunk 1.7, которое позволяет использовать реальный размер для формы. Чтобы использовать его, просто скомпилируйте свое приложение с помощью <tt>LCLRealFormBounds ON</tt>. Пока что поддерживается только widgetset win32.
  
 +
Для всех остальных элементов управления применяются правила ClientWidth<=Width. Width - это ClientWidth плюс рамка виджета. Вопрос в том, принадлежат ли полосы прокрутки рамке. Я бы сказал "да", и это было реализовано таким образом некоторое время назад. Видимо, это изменилось. См. Текущую проблему с курсором в synedit."
  
==I get an infinite loop / How to debug autosizing?==
+
==Я получаю бесконечный цикл / Как отладить автомасштабирование?==
  
Here are some notes, what other users made wrong and how to find out:
+
Вот некоторые примечания, что другие пользователи сделали неправильно и как найти выход:
  
===Differences to Delphi===
+
===Отличия от Delphi===
For Delphi users: Please read: [[Autosize_/_Layout#Difference_to_Delphi|Difference to Delphi]]
+
Для пользователей Delphi: пожалуйста, прочитайте: [[Autosize_/_Layout/ru#Отличия от Delphi|Отличия от Delphi]]
  
===Overriding a LCL method and triggering a recompute===
+
===Переопределение метода [[LCL/ru|LCL]] и запуск пересчета===
  
You override a method and tell the LCL to compute again, even if nothing changed. Check for AdjustSize, Realign, AlignControls, InvalidatePreferredSize. For example:
+
Вы переопределяете метод и просите [[LCL/ru|LCL]] пересчитать снова, даже если ничего не изменилось. Проверьте настройки AdjustSize, Realign, AlignControls, InvalidatePreferredSize. Например:
  
<syntaxhighlight>procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
+
<syntaxhighlight lang="pascal">
 +
procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
 
begin
 
begin
   // This will create an endless loop
+
   // Это создаст бесконечный цикл
 
   InvalidatePreferredSize;
 
   InvalidatePreferredSize;
  
   // This will create an endless loop too:
+
   // Это также создаст бесконечный цикл:
 
   OtherComponent.Left:=10;
 
   OtherComponent.Left:=10;
 
   OtherComponent.Left:=20;
 
   OtherComponent.Left:=20;
Line 1,100: Line 1,140:
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
Explanation: The SetBounds method is called often, even without changing anything. For example a "Left:=30;" will do so.
+
Объяснение: метод SetBounds вызывается часто, даже ничего не меняя. Например, так будет делать "Left:=30;".
  
Remedy: Check for changes:
+
Решение: отслеживайте изменения:
  
<syntaxhighlight>procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
+
<syntaxhighlight lang="pascal">
 +
procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
 
begin
 
begin
 
   if (Left <> ALeft) or (Top <> ATop) or (Width <> AWidth) or (Height <> AHeight) then
 
   if (Left <> ALeft) or (Top <> ATop) or (Width <> AWidth) or (Height <> AHeight) then
Line 1,113: Line 1,154:
 
====TWinControl.AlignControls====
 
====TWinControl.AlignControls====
  
<code>
+
<syntaxhighlight lang="pascal">
 
procedure AlignControls(aControl: TControl; var aRect: TRect); override;
 
procedure AlignControls(aControl: TControl; var aRect: TRect); override;
</code>
+
</syntaxhighlight>
  
AlignControls moves and sizes all child controls. The LCL implementation ignores controls with Align=alCustom.
+
AlignControls перемещает и упорядочивает все дочерние элементы управления. Реализация [[LCL/ru|LCL]] игнорирует элементы управления с помощью Align=alCustom.
  
The parameter aControl: TControl is kept for VCL compatibility. The LCL always passes nil. It gives aControl precedence when applying the Align property.
+
Параметр <tt>aControl: TControl</tt> поддерживается для совместимости с VCL. [[LCL/ru|LCL]] всегда возвращает nil. Он дает приоритет aControl при применении свойства Align.
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.
+
Если у вас есть, например, два элемента управления A,B со [значением] Align=alLeft, то [элемент управления, который будет] нижним слева расположится левее [другого]. Если оба имеют одинаковые [значения] Left, [то] приоритетнее [элемент в] порядке создания.
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.
+
Теперь представьте, что вы хотите переключить оба элемента управления A, B в дизайнере. Вы перетащите B влево. Это приведет к установке [значения] B.Left в 0. Теперь AlignControls запускается и находит[, что у обоих элементов управления значения] A.Left=0 и B.Left=0. В обычном [случае] A [по расположению окажется в] приоритете.
To let B win the VCL calls AlignControls(B,r).
+
Чтобы [приоритетнее оказался элемент управления] B, VCL вызовет AlignControls(B,r).
So aControl is the last moved.
+
Таким образом, aControl является последним перемещенным.
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.
+
В отличие от VCL, [[LCL/ru|LCL]] позволяет комбинировать несколько изменений разметки без перерасчета на каждом шагу. [[LCL/ru|LCL]] отслеживает последние перемещенные элементы управления в TWinControl.fAlignControls и применяет порядок в TWinControl.CreateControlAlignList. Параметр aControl всегда равен nil.
  
See TWinControl.CreateControlAlignList.
+
Смотри <tt>TWinControl.CreateControlAlignList</tt>.<br />
  
===OnResize/OnChangeBounds conflict with LCL properties===
+
===OnResize/OnChangeBounds конфликтует со свойствами LCL===
You 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:
+
Вы устанавливаете границы, которые ущемляют свойства LCL. Например, по умолчанию TLabel.AutoSize [имеет значение] true. Если вы определяете Label1.Width в событии OnResize, LCL будет [запускать] пересчет, изменяя размер Label1, и снова вызывать OnResize. Запустите приложение в отладчике и воспроизведите ошибку. Когда оно войдет в [бесконечный] цикл, приостановите приложение и смотрите стек вызовов. Как вы видите, одно из ваших событий или ваших методов начинают искать там. Например:
  
<syntaxhighlight>procedure TMainForm.FormResize(Sender: TObject);
+
<syntaxhighlight lang="pascal">
 +
procedure TMainForm.FormResize(Sender: TObject);
 
begin
 
begin
   // if Button1 is anchored or AutoSize=true then the following might create an endless loop:
+
   // если Button1 привязан или AutoSize=true, то следующее может создать бесконечный цикл:
 
   Button1.Width:=100;
 
   Button1.Width:=100;
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
===LCL interface bug, custom widget===
+
===Ошибка интерфейса LCL, пользовательский виджет===
Sometimes 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.
+
Иногда интерфейс LCL или ваш пользовательский элемент управления имеет ошибку и отменяет границы LCL. Скомпилируйте LCL с [опцией] <tt>-dVerboseIntfSizing</tt>. Это запишет связь между LCL и интерфейсом LCL. Если виджет не допускает свободное изменение размера, он должен сказать [об этом] LCL через Constraints[(ограничения)]. Поищите <tt>SetInterfaceConstraints</tt> в различных интерфейсах LCL и <tt>TWSControlClass.ConstraintWidth/Height</tt>.
  
 
===alCustom===
 
===alCustom===
You 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|alCustom]].
+
Вы используете alCustom. В ранних версиях Lazarus это было реализовано только наполовину, но некоторые даровитые программисты использовали его для создания некоторых специальных эффектов. Теперь это реализовано, и ваша программа больше не работает. Пожалуйста, см. здесь, что alCustom делает: [[Autosize_/_Layout/ru#alCustom|alCustom]].
  
=See also=
+
=См. также=
  
 
* [[Docking]]
 
* [[Docking]]
* [[Anchor Sides]]
+
* [[Anchor_Sides/ru|Anchor Sides]]
 
 
[[Category:Russian]]
 
[[Category:Russian (unfinished translation)]]
 
[[Category:LCL/ru]]
 
[[Category:GUI/ru]]
 
[[Category:Multiplatform Programming/ru]]
 
[[Category:Platform-sensitive development/ru]]
 

Latest revision as of 16:04, 5 September 2023

English (en) русский (ru) 中文(中国大陆)‎ (zh_CN) 中文(台灣)‎ (zh_TW)


Введение

LCL может автоматически изменять размер и положение элемента управления, поэтому он адаптируется к изменениям шрифта, темы и текста или другого содержимого. Если вы хотите запустить программу на нескольких платформах, или если ваши подписи доступны на нескольких языках, то ваши средства управления должны правильно адаптироваться к своей среде. LCL позволяет не только сделать быстрый начальный дизайн (перемещение элементов управления на форму с помощью мыши), но и позже установить несколько ключевых свойств, которые сделают регуляторы автоматически адаптироваться впоследствии измененным содержанием и т.д.

  • Фиксированный дизайн (Fixed design): это значение по умолчанию при размещении элемента управления в дизайнере форм. Положение элемента управления фиксируется относительно его родителя. Размер и положение элемента управления (Left, Top) полностью изменяются программистом. Вы можете перемещать элемент с помощью мыши и изменять его размер свободно.
  • Выравнивание (Aligned): выравненные элементы управления заполняют оставшееся пространство родителя вверху, снизу, слева или справа, или заполняют всё оставшееся пространство.
  • Привязка (Anchored): вы можете закрепить стороны элемента управления (слева, сверху, справа, снизу) с его родителем или с другим элементот управления. Закрепление: LCL попытается оставаться на таком же расстоянии от точки привязки.
  • Разметка (Layout): элементы управления могут быть автоматически выровнены по строкам и столбцам (например, TRadioGroup)
  • Пользовательская разметка через OnResize/OnChangeBounds: можно выровнять элементы управления самостоятельно в коде, используя события OnResize и OnChangeBounds.
  • Пользовательские элементы управления: написав собственные элементы управления, вы можете переопределить почти каждое поведение LCL как вы хотите.

Правила приоритета

  1. Constraints (Ограничения)
  2. Align (Выравнивание)
  3. Anchors(Привязки)
  4. ChildSizing.Layout
  5. AutoSize (Автомасштаб элемента)
  6. События OnResize, OnChangeBounds - однако, если вы установите границы, которые конфликтуют с вышеуказанными правилами, то это создаст бесконечный цикл

Общие свойства

Чтобы настроить автоматическое изменение размера, можно изменить несколько основных свойств :

  • Left, Top, Width, Height
  • AutoSize: Автомасштаб, указывает LCL автоматически изменить ширину и высоту элемента управления
  • Anchors: позволяет создавать зависимости, например, чтобы привязать ComboBox к правой стороне #Label.
  • Align
  • Constraints: позволяет установить минимум и максимум для ширины и высоты
  • BorderSpacing: позволяет установить расстояние между привязанными элементами управления
  • ChildSizing: позволяет установить расположение и расстояние дочерних элементов управления

Внутренние алгоритмы объясняются здесь: LCL AutoSizing.

Фиксированный дизайн

Фиксированный ​​дизайн установлен по умолчанию. Якорь установлен в значение [akLeft, akTop], что означает, значения Top и Left не будут изменяться LCL. Если значение AutoSize равно False, LCL не изменяет ширину или высоту. Если значение AutoSize равно True, то ширина и высота изменяются по размеру содержимого. Например, TLabel.AutoSize умолчанию True, поэтому при изменении текста в нем будет соответственно изменяться размер и TLabel, чтобы измененный текст поместился в контроле полностью. TButton.AutoSize умолчанию установлен в False, таким образом изменение надписи на кнопке не изменит размеры кнопки. При установке значения Button.AutoSize в True, кнопка будет уменьшаться или увеличиваться каждый раз при изменении Caption на кнопке или при изменении шрифта или темы. Обратите внимание, что это изменение не всегда происходит сразу. Например во время FormCreate всё автоизмение размера приостанавливается. В любой момент вы можете изменить свойства Left, Top, Width и Height.

Автомасштаб

AutoSize(автомасштаб) - логическое свойство во многих классах; оно позволяет отрегулировать размер элемента управления автоматически, учитывать изменения в тексте или графике, содержащейся в нем, и позволяет наиболее эффективно использовать имеющееся пространство. Это очень важный механизм для создания кроссплатформенных форм.

Обычно AutoSize равенTrue и делает две вещи для видимого элемента управления:

  • Если возможно, изменяет управление в нужный размер. Например ширина и высота TButton изменяется в соответствии с надписью, в то время как TEdit изменяется только в высоту. Ширина TEdit не изменяется автоматически. Вы можете изменить ширину TEdit самостоятельно.(см GetPreferredSize).
  • Оно передвигает все фиксированно расположенные дочерние элементы управления так, чтобы самый левый дочерний элемент управления имел Left = 0 (зависит от значения свойства BorderSpacing) и самый верхний дочерний элемент управления имел Top = 0.

Отличия от Delphi

  • AutoSize в Delphi происходит только тогда, когда определенные свойства изменяются, например, когда шрифт из TLabel изменяется. В LCL AutoSize всегда активен. Delphi позволяет изменить размер TLabel, который имеет AutoSize = True, LCL - нет.
  • Скрытые управления не изменяют размер автоматически.
  • Изменение размера элемента управления не изменяет размер/расположение заякоренных(привязанных) дочерних элементов управления во время загрузки. Имейте в виду, что конструкторы элементов управления можно вызвать во время загрузки. При использовании akRight, akBottom якоря с установленными AnchorSides и BorderSpacing сохраняют правильное расстояние.

Автомасштаб и изменение размера элемента управления

С помощью свойства кнопки AutoSize=false задаются фиксированный размер по умолчанию.

Autosize1.png

При установке AutoSize=true для каждой кнопки, кнопки растягиваются (или сжимаются) в соответствии с текстом и темой.

Autosize on.png

AutoSize не сжимает элемент управления до минимально возможного размера, как вы можете видеть по кнопке OK. Он использует метод GetPreferredSize элемента управления, который вызывает метод CalculatePreferredSize. По умолчанию реализация TWinControl запрашивает виджетсет, который может иметь оптимальную ширину или высоту. Каждый элемент управления может переопределять метод CalculatePreferredSize. Например, TImage переопределяет его и возвращает размер изображения. Если нет оптимальной ширины (высоты), возвращаемое значение равно 0, и LCL будет хранить ширину(высоту) элемента управления (если не установлен флаг ControlStyle = csAutoSize, который в настоящее время используется только TPanel).

TWinControl вычисляет размер всех своих дочерних элементов управления и использует это для вычисления своего оптимального размера.

Когда элемент управления привязан как слева, так и справа, его ширина фиксирована. Например, со значением привязки Align=alTop элемент управления привязан слева и справа, и соответствует ширине Родителя. Если Parent.AutoSize имеет значение true, тогда Родитель будет использовать оптимальную ширину элемента управления для вычисления своей собственной оптимальной ширины, и, таким образом, размер элемента управления будет изменен до его оптимальной ширины. См. Выравнивание и свойство AutoSize. Если значение оптимальной ширины недоступно, используются последние установленные границы (BaseBounds или ReadBounds). Если никаких ограничений не было установлено, используется метод GetControlClassDefaultSize. То же самое для свойства Height и привязки сверху и снизу.

Ограничения применяются всегда и имеют приоритет.

Автомасштаб и перемещение дочерних элементов управления

Когда AutoSize=false, вы можете размещать и перемещать элементы управления свободно:

Autosize on.png

Когда AutoSize=true, дочерние элементы управления с фиксированным положением перемещаются с подгонкой.



Прим.переводчика: на самом деле, перемещаются границы родительского элемента управления так, чтобы дочерние элементы управления с фиксированной относительно друг друга позицией полностью умещались на родительском. При этом родительский элемент управления будет иметь минимально возможный размер. Таким образом, кнопки "перемещаются" относительно верхнего левого угла родительского элемента управления.



Autosize panel on.png

Обе кнопки на панели были перемещены влево и кверху на одно и то же значение так, чтобы сверху и слева не оставалось свободного пространства. Если будут установлены свойства BorderSpacing>0 (у кнопок) или Panel.ChildSizing.LeftRightSpacing>0 (у панели), то кнопки будут перемещены так, чтобы предопределенный в упомянутых выше свойствах зазор был задействован.

Могут быть перемещены дочерние элементы управления только со следующими свойствами:

  • Anchors=[akLeft,akRight]
  • AnchorSide[akLeft].Control=nil
  • AnchorSide[akTop].Control=nil
  • Align=alNone

Перемещение дочерних элементов управления зависит от свойства ChildSizing.Layout. Разметка применяется в методе TWinControl.AlignControls, который может быть полностью или частично переопределен. Например, TToolBar переопределяет ControlsAligned, чтобы разместить все элементы управления со значением свойства Align=alCustom, и задает разметку для перемещения на следующие линии не "вписавшимся" в родительский контрол дочерним элементам управления.

Родительские элементы управления могут отключать перемещение дочерних элементов управления установкой у свойства ControlStyle флагов csAutoSizeKeepChildLeft и csAutoSizeKeepChildTop (начиная с 0.9.29).

Автомасштаб и формы

Формы без Parent родительского элемента управления управляются диспетчером окон и, следовательно, не могут свободно размещены или перемещены. Изменение размера в RunTime является лишь рекомендацией, и может быть проигнорировано диспетчером окон. Например, вы можете устанавливать ширину формы 1000 px, а widgetset в ответ изменит размер к 800 px. Если вы устанавливаете свойство Witdh в событии формы OnResize, то можете создать бесконечное зацикливание. Вот почему LCL TForm отключает AutoSize, когда widgetset изменяет размеры формы.

Это означает, что действие свойства AutoSize для форм приостанавливается, когда пользователь изменяет размер формы или если диспетчеру окон не нравятся текущие границы окна. Например, некоторые диспетчеры окон в Linux имеют такие фишки, как "прилипающие" края, которые изменяют размеры текущего окна в привязке к другим окнам.

Принудительная установка автомасштабирования формы

Вы можете выставить новое значение свойства AutoSize, выполнив:

Form1.AutoSize := False;
Form1.AutoSize := True;

Расчет размера формы с "автомасштабом" заранее

При размещении формы с "автомасштабом" (очевидно, имеется ввиду Form1.AutoSize=True) вам может потребоваться получить размер формы, прежде чем показывать ее. Для установки автомасштаба требуется дескриптор (хэндл окна). Вы можете рассчитать размер формы прежде, чем ее показывать, с помощью:

Form1.HandleNeeded;
Form1.GetPreferredSize(PreferredWidth,PreferredHeight);
Light bulb  Примечание: Диспетчер окон и события формы могут изменять размер окна. Предпочтительный размер не включает рамку окна формы. Это запланированная особенность.



Привязка сторон (Anchoring)

Элементы управления для привязки к четырем сторонам имеют свойство Anchors с возможными значениями: akLeft, akTop, akRight и akBottom. Каждая сторона может быть привязана к родителю или к стороне другого собрата (элемент управления с одним и тем же родителем). Привязка означает сохранение расстояния между привязанными элементами управления. По умолчанию значение свойства Anchors = [akLeft, akTop]. Вертикальные привязки не зависят от горизонтальных привязок. Некоторые свойства, такие как Align и Parent.AutoSize имеют более высокий приоритет, и могут изменять поведение.

Привязка к родителю или nil

Привязка к nil (по умолчанию) имеет почти такой же эффект, как привязка к родителю. Оба пытаются сохранять расстояние до края клиентской области Родителя. Для привязки к Nil используется расстояние от последнего вызова SetBounds, в то время как для привязки к родительскому используется значение BorderSpacing.

Существует четыре комбинации akLeft, akRight (akTop, akBottom):

  • akLeft, no akRight: Left контрола фиксирован и не может быть изменен LCL. Правая сторона не закреплена, поэтому она следует за левой стороной. Это означает, что Width также сохраняется.
  • akLeft and akRight: Left элемента управления фиксирован и не может быть изменен LCL. Правая сторона привязана к правой стороне Родителя. Это означает, что если Родитель увеличен на 100 пикселей, тогда Width контрола также будет увеличена на 100 пикселей.
  • akRight, no akLeft: левая сторона управления не закреплена, поэтому она будет следовать за ее правой стороной. Правая сторона закреплена. Это означает, что если Родитель увеличится на 100 пикселей, тогда контроле перемещается вправо на 100 пикселей.
  • no akLeft and no akRight: ни одна из сторон не закреплена. Положение центра контрола масштабируется с родителем. Например, если контрол находится в середине родительского элемента, а родительский элемент увеличен на 100 пикселей, тогда контрол перемещается на 50 пикселей вправо.

Изменение размера родителя с привязанным контролом

При изменении размера родителя все привязанные дочерние контролы перемещаются и/или изменяются по размеру сразу, пока не будет отключено свойство AutoSizing. Например, AutoSizing отключается во время загрузки формы и при создании формы.

GroupBox с кнопкой: Anchors1.png

Когда GroupBox увеличивается в размере, расстояние до привязанной стороны сохраняется:

С akLeft, без akRight: Anchors akLeft.png

С akLeft и akRight: Anchors akLeft akRight.png

С akRight, без akLeft: Anchors akRight no akLeft.png

Три кнопки в GroupBox: Anchors no akLeft no akRight small.png

Без akLeft и без akRight их центры масштабируются: Anchors no akLeft no akRight big.png


На заметку:

  • Загрузка формы похожа на один большой SetBounds. Во время загрузки свойства задаются с использованием значений , сохраненных в файле формы lfm. Имейте в виду, что из-за предков и фреймов может быть несколько файлов lfm. После загрузки LCL активирует autosizing. Привязанные контролы используют ограничение в конце загрузки. Любой шаг между ними игнорируется.
  • Для пользовательских контролов часто лучше устанавливать AnchorSides вместо Anchors.

Изменение размера привязанного элемента управления

При изменении ширины привязанного элемента управления, например, через Object Inspector или через код Button1.Width:=3, вы можете увидеть разницу между привязкой к "родителю" и привязкой к "nil". Привязка к родителю будет изменять размер и перемещать Button1, а привязка к nil будет только изменять размер. Например:

Привязка к nil

Anchored right nil resize1.png Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=nil

Anchored right nil resize2.png Установка ширины на меньшее значение приведет к сужению кнопки, сохраняя значение Left кнопки, увеличивая расстояние от правой стороны кнопки до правого края.

Anchored right nil resize3.png При изменении размера Groupbox кнопка сохранит новое расстояние до правого края.

Объяснение: установка значения Width кнопки эквивалентна вызову SetBounds(Left,Top,NewWidth,Height). Вот почему значение Left сохраняется. Это совместимо с поведением контролов в Delphi.

Привязка к родителю

Anchored right parent resize1.png Кнопка Button1 привязана [akTop,akRight], AnchorSide[akRight].Control=Button1.Parent

Anchored right parent resize2.png Установка значения Width на меньшее значение приведет к сужению кнопки, сохранив расстояние от ее правой границы до края компонента-родителя и изменив значение Left кнопки.

Привязка к соседу

Вы можете привязываться к соседним элементам управления. Следующий пример показывает, что:

  • вы можете привязать левый край label'а к левому краю кнопки
  • привязать верхний край label'а к нижнему краю кнопки
  • привязать центр label'а к центру кнопки

Anchorsides example1.png

Anchorside example2.png

Подробнее о том, как установить привязку, см. Стороны привязки.

Anchoreditor.png

Зазор

Свойство BorderSpacing(зазор) управляет минимальным количеством пространства вокруг элемента управления. Свойства:

  • Around: эта величина в пикселах, которая добавляется к каждому значению Left, Top, Right, Bottom элемента управления.
  • Left: зазор в пикселах с левой стороны элемента управления
  • Top: зазор в пикселах сверху элемента управления
  • Right: зазор в пикселах с правой стороны элемента управления
  • Bottom: зазор в пикселах под элементом управления
  • InnerBorder: это зазор в пикселях, добавляется дважды к оптимальной ширине и высоте. Некоторые элементы управления переопределяют вычисление и игнорируют это свойство. Пример, где он работает, - TButton. С помощью InnerBorder вы можете сделать кнопку больше, чем необходимо.
  • CellAlignHorizontal: Этот параметр используется в табличных макетах, таких как ChildSizing.Layout=cclLeftToRightThenTopToBottom. Если элемент управления меньше ячейки таблицы, это свойство определяет, как выровнять элемент управления: слева ccaLeftTop, справа ccaRightBottom или посередине ccaCenter.
  • CellAlignVertical: так же, как CellAlignHorizontal, но для вертикального выравнивания.

Правила зазоров

  • Значение Around добавляется к зазору для Left,Top,Right,Bottom элемента управления.
  • Зазор может быть еще больше, если элементы управления имеют ограничения, которые не позволяют им растягиваться.

Привязка к противоположной стороне

Например, правая сторона A к левой стороне B.

Используются обе границы A и B.

  • Горизонтальный зазор между двумя элементами управления (LeftControl, RightControl на общем родителе) он максимален, если:
    • LeftControl.BorderSpacing.Right + LeftControl.BorderSpacing.Around
    • RightControl.BorderSpacing.Left + RightControl.BorderSpacing.Around
    • Parent.ChildSizing.HorizontalSpacing
  • Вертикальный зазор работает аналогично: между двумя элементами управления (TopControl, BottomControl на общем родителе) он максимален, если:
    • TopControl.BorderSpacing.Bottom + TopControl.BorderSpacing.Around
    • BottomControl.BorderSpacing.Top + BottomControl.BorderSpacing.Around
    • Parent.ChildSizing.VerticalSpacing

Например:

  • если LeftControl.BorderSpacing.Right=3 и LeftControl.BorderSpacing.Around=4, то между двумя элементами управления должно быть не менее 7px
  • если RightControl.BorderSpacing.Left=4 и RightControl.BorderSpacing.Around=4, то пространство будет не менее 8px
  • если Parent.ChildSizing.HorizontalSpacing=10, тогда пространство будет не менее 10px

Привязка к этой же стороне

Например, правая сторона A к правой стороне B.

  • Задействуется только зазор у границы А.
  • Свойство Parent.ChildSizing.Horizontal/VerticalSpacing не используется.

Привязка к центру

Например, центр А привязан к центру В.

Не задействуются ни зазор, ни свойство Parent.ChildSizing.Horizontal/VerticalSpacing.

Пример

Общим примером является привязка Label'а к Edit'у.

BorderSpacing Anchors.png

Центр Label'а вертикально привязан к Edit'у. Левая сторона Edit'а привязана к правой стороне Label'а. Оба имеют BorderSpacing.Around=6. Это приводит к наличию зазора в 6px между Label'ом и Edit'ом и наличию зазора в 6px слева от Label'а, а также наличию зазора в 6px справа от Edit'а. Также еще существует 6 пикселей зазора выше и ниже Edit'а.

  • Зазор слева между элементом управления и его родителем (Label1 к GroupBox1) является максимальным, когда
    • Label1.BorderSpacing.Left + Label1.BorderSpacing.Around
    • GroupBox1.ChildSizing.LeftTopSpacing
  • Зазор справа между элементом управления и его родителем (Edit1 к GroupBox1) является максимальным, когда
    • Edit1.BorderSpacing.Right + Edit1.BorderSpacing.Around
    • GroupBox1.ChildSizing.RightBottomSpacing
  • Когда центр элемента управления привязан к другому элементу управления, например, вышеуказанный Label центрирован по вертикали к Edit1, тогда все остальные зазоры игнорируются.
  • Когда левая сторона элемента управления привязана к левой стороне другого элемента управления (т.е., они выровнены по левой стороне), то расстояние между обеими левыми сторонами является
    • Control1.BorderSpacing.Left + Control1.BorderSpacing.Around


Вот более сложный пример:

Borderspacing anchors2.png

Важные части кода lfm:

  object GroupBox1: TGroupBox
    AutoSize = True
    Caption = 'GroupBox1'
    TabOrder = 0
    object Label1: TLabel
      AnchorSideLeft.Control = GroupBox1
      AnchorSideTop.Control = Edit1
      AnchorSideTop.Side = asrCenter
      BorderSpacing.Around = 6
      Caption = 'Label1'
    end
    object Edit1: TEdit
      AnchorSideLeft.Control = Label1
      AnchorSideLeft.Side = asrBottom
      AnchorSideTop.Control = GroupBox1
      AnchorSideRight.Control = GroupBox1
      AnchorSideRight.Side = asrBottom
      Anchors = [akTop, akLeft, akRight]
      BorderSpacing.Around = 6
      TabOrder = 0
      Text = 'Edit1'
    end
    object Label2: TLabel
      AnchorSideLeft.Control = GroupBox1
      AnchorSideTop.Control = Edit1
      AnchorSideTop.Side = asrBottom
      BorderSpacing.Around = 6
      Caption = 'Label2'
    end
    object ComboBox1: TComboBox
      AnchorSideLeft.Control = Label2
      AnchorSideTop.Control = Label2
      AnchorSideTop.Side = asrBottom
      AnchorSideRight.Control = GroupBox1
      AnchorSideRight.Side = asrBottom
      Anchors = [akTop, akLeft, akRight]
      BorderSpacing.Right = 6
      TabOrder = 1
      Text = 'ComboBox1'
    end
    object CheckBox1: TCheckBox
      AnchorSideLeft.Control = GroupBox1
      AnchorSideTop.Control = ComboBox1
      AnchorSideTop.Side = asrBottom
      BorderSpacing.Around = 6
      Caption = 'CheckBox1'
      TabOrder = 2
    end
    object Label3: TLabel
      AnchorSideLeft.Control = GroupBox1
      AnchorSideTop.Control = Edit2
      AnchorSideTop.Side = asrCenter
      BorderSpacing.Around = 6
      Caption = 'Label3'
    end
    object Edit2: TEdit
      AnchorSideLeft.Control = Label3
      AnchorSideLeft.Side = asrBottom
      AnchorSideTop.Control = CheckBox1
      AnchorSideTop.Side = asrBottom
      BorderSpacing.Around = 6
      TabOrder = 3
      Text = 'Edit2'
    end
  end

Зазор и выравнивание

Зазор работает с выравниванием. В приведенном ниже примере есть Memo1 с Align=alTop и Memo2 с Align=alCLient.

  • Обычно два Memo заполняют весь GroupBox.
  • Но Memo1 имеет BorderSpacing.Around=10, так что вокруг Memo1 будет присутствовать зазор в 10 пикселей.
  • Memo2 имеет BorderSpacing.Top=20. Зазор между Memo1 и Memo2 будет максимальным, который от Memo1 до Memo2 составит 20px.
  • Memo2 также имеет и BorderSpacing.Right=50, поэтому справа от Memo2 имеется зазор в 50 пикселей.
  • GroupBox может задавать зазор по умолчанию для всех своих дочерних элементов управления через значения свойств ChildSizing.LeftRightSpacing/VerticalSpacing/HorizontalSpacing. В этом примере их нет (все упомянутые значения равны 0).

Borderspacing align1.png

Выравнивание (Aligned)

Свойство Align(выравнивание) работает почти так же, как в Delphi, и может использоваться для быстрого заполнения какой-нибудь области. Например, чтобы TListBox заполнил всю область своего родителя, установите ListBox1.Align=alClient. Значения выравнивания alTop, alBottom, alLeft и alRight будут размещать элементы управления по возможности без перекрытия друг друга. Это означает, что все элементы управления свойства Align со значением alLeft, alTop, alBottom, alRight не будут перекрываться, если есть достаточно места.

Алгоритм работает следующим образом:

  • Сначала все элементы управления с помощью значения свойства alTop помещаются в верхнюю часть клиентской области. Если имеется несколько элементов управления с помощью alTop, последний добавленный/перемещенный будет помещен выше всех. Алгоритм будет стараться избегать перекрытия и сохранять высоту элемента управления, пока ширина всех элементов остается максимальной. Стороны привязки левой, верхней и правой сторон игнорируются. Нижняя сторона привязки работает нормально. Зазор и значение свойства Parent.ChildSize просчитываются, поэтому вы можете задавать зазор вокруг каждого выровненного элемента управления.
  • Затем все элементы управления с помощью значения свойства alBottom помещаются в нижнюю часть клиентской области. В противном случае оно работает аналогично alTop.
  • Потом все элементы управления с помощью значения свойства alLeft помещаются слева от клиентской области между элементами управления alTop и alBottom. В противном случае оно работает аналогично alTop.
  • Затем все элементы управления с помощью значения свойства alRight помещаются справа от клиентской области между элементами управления alTop и alBottom. В противном случае оно работает аналогично alTop.
  • Если есть элемент управления с установленным свойством alClient, он заполнит оставшуюся часть клиентской области.
  • Если имеется более одного элемента управления с установленным свойством alClient, они будут помещаться в одно и то же положение, перекрывая друг друга. Используйте свойство Visibility, чтобы определить, какой из них будет показан.

Autosize align.png

Выравнивание и зазоры

Величина свойства BorderSpacing и свойства ChildSize родителя применяется к выравниваемым элементам управления. Элемент управления memo ниже имеет Align=alClient.


Прим.переводчика: Ох, уж эти языковые особенности. Автор, очевидно, имел в виду следующее: даже если у дочернего контрола выравнивание выставлено как Align=alClient, то он не будет заполнять собой контрол-родитель полностью, если его свойство BorderSpacing или свойство ChildSize родителя имеют ненулевое значение.



Autosize align borderspacing.png

Выравнивание и Привязка

Свободная сторона выровненного элемента управления (напр., правая сторона Align=alLeft) следует правилам привязки. Если привязка не установлена, тогда элемент управления будет сохранять значение своей Width. Если привязка установлена, то значение Width изменится.

Выравнивание и свойство AutoSize

Элемент управления, выровненный посредством alLeft или alRight, растягивается по вертикали и будет использовать свою ширину, определенную на этапе проектирования формы. Если свойство AutoSize установлено в true, то значение параметра Width будет оптимальной шириной. Кнопка снизу имеет Align=alRight и AutoSize=true.

Autosize align autosize.png

Выравнивание и свойство AutoSize родителя

Элемент управления, выровненный посредством alClient, заполняет оставшееся пространство. Родительский элемент управления со значением свойства AutoSize=true при этом будет растягиваться или сжиматься так, чтобы впритирку умещать на себе свои дочерние элементы. Что произойдет, если вы объедините эти два свойства? Скажем, вы положили кнопку с Align=alClient на groupbox с AutoSize=true?

Autosize nested1.png

LCL использует предпочтительный размер кнопок и потому растягивает или сжимает groupbox:

Autosize nested2.png

alCustom

Это значение Align существует для пользовательских алгоритмов AutoSize и обрабатывается LCL почти как alNone. Элементы управления с установленным значением alCustom не перемещаются LCL, но могут быть перемещены вашим пользовательским элементом управления. Для этого вы должны переопределить методы CalculatePreferredSize и DoAutoSize.

Порядок расположения элементов управления с одинаковым значением Align

Элементы управления с одинаковым выравниванием добавляются в следующем порядке. Для alLeft элемент управления с наименьшим значением Left, для alTop - наименьшим значением Top, для alRight - наибольшая величина Left+Width, для alBottom - наибольшая величина Top+Height. Если два элемента управления имеют одну и ту же координату, последний из них одерживает победу (вызывая SetBounds или SetParent). Элементы управления могут переопределять CreateControlAlignList, чтобы изменить порядок или переопределить DoAlignChildControls для обработки всего Align.

Light bulb  Примечание: до версии Lazarus 0.9.29 элементы управления размещались в Z-порядке. В некоторых случаях это приводило к переупорядочиванию элементов управления и должно было быть исправлено. Существует одна несовместимость: если вы добавили несколько элементов управления с выравниванием alTop или alLeft без указания границ, все элементы управления будут помещены в координаты 0.0, и, следовательно, последние добавленные окажутся поверх контролов, добавленных ранее.



Разметка (Layout)

Строки, столбцы и строки

Вы можете выравнивать дочерние элементы управления в строках и столбцах, используя свойства ChildSize. Например:

  • ChildSizing.Layout=cclLeftToRightThenTopToBottom
  • ChildSizing.ControlsPerLine=3
  • AutoSize=false (не изменяет размеры, чтобы подстраиваться под дочерние элементы управления)

Autosize layout lefttoright.png

Свойство Layout по умолчанию [имеет значение] cclNone. Если вы установите Layout в другое значение, каждый дочерний элемент, имеющий нормальные привязки, будет выровнен. Нормальные привязки означают:

  • Anchors=[akLeft,akTop]
  • AnchorSide[akLeft].Control=nil
  • AnchorSide[akTop].Control=nil
  • Align=alNone

Значение cclLeftToRightThenTopToBottom будет помещать первый дочерний элемент управление вверху [и] слева, второй - [вверху и] правее, и так далее. Это - линия. Свойство ControlsPerLine определяет, когда начинается новая строка. В приведенном выше примере каждая линия (строка) имеет 3 элемента управления. Существует [всего] 12 элементов управления, поэтому есть 4 линии (строки), каждая из которых имеет [по] 3 элемента управления (столбцы). Если ControlsPerLine равен 0, это означает неограниченное количество элементов управления в строке - будет только одна строка со всеми дочерними элементами.

Вы можете видеть, что строки имеют разные размеры, каждая строка имеет размер самого большого элемента управления и что элементы управления изменяют размеры до ширины столбца. Между строками нет пробела. Пространство в изображении определяется используемой темой, а не [приходит] из LCL.

Фиксированные зазоры между строками и столбцами

Вы можете добавить зазоры между [строками и столбцами] этими свойствами:

  • ChildSizing.VerticalSpacing - зазор между строками
  • ChildSizing.HorizontalSpacing - зазор между столбцами
  • ChildSizing.LeftRightSpacing - зазор между левой и правой [стороной] всех столбцов
  • ChildSizing.TopBottomSpacing - зазор выше и ниже всех столбцов

Выше приведенный пример с [параметрами]:
ChildSizing.VerticalSpacing=6,
ChildSizing.HorizontalSpacing=15,
ChildSizing.LeftRightSpacing=30,
ChildSizing.TopBottomSpacing=10,
AutoSize=true

Autosize layout parentspacing.png

Кроме того, вы можете добавить зазор для каждого элемента управления отдельно с [помощью] его свойства BorderSpacing.

Растяжение

Приведенный выше пример изменяет размер GroupBox до необходимых размеров. Если ваш GroupBox имеет фиксированный размер или если он не является свободно изменяемым, например, если GroupBox должен заполнять всю ширину формы, то дочерние элементы должны растягиваться. Существует несколько режимов. Режим по умолчанию ChildSizing.EnlargeHorizontal=crsAnchorAligning запрещает что-либо растягивать. Зазоры с правой стороны не будут использоваться.

  • crsAnchorAligning - не использует дополнительные зазоры
  • crsScaleChilds - умножает ширину/высоту на тот же коэффициент
  • crsHomogeneousChildResize - добавляет к каждой ширине/высоте ту же величину
  • crsHomogeneousSpaceResize - добавляет к каждому зазору между дочерними элементами ту же величину

crsScaleChilds

ChildSizing.EnlargeHorizontal=crsScaleChilds
ChildSizing.EnlargeVertical=crsScaleChilds
AutoSize=false

Autosize layout scalechilds.png

Например, если значение ClientWidth вдвое больше необходимого, то каждый дочерний элемент будет в два раза больше.

crsHomogeneousChildResize

ChildSizing.EnlargeHorizontal=crsHomogeneousChildResize
ChildSizing.EnlargeVertical=crsHomogeneousChildResize
AutoSize=false

Autosize layout homogeneouschildresize.png

Например, если ClientWidth на 30 пикселей больше, чем нужно, то каждый дочерний элемент будет на 10 пикселей шире.

crsHomogeneousSpaceResize

ChildSizing.EnlargeHorizontal=crsHomogeneousSpaceResize
ChildSizing.EnlargeVertical=crsHomogeneousSpaceResize
AutoSize=false

Autosize layout homogeneousspaceresize.png

Например, если ClientWidth на 40 пикселов больше, чем необходимо, появится [дополнительно по] 10 пикселей зазора слева, справа и между каждым дочерним элементом.

Сжатие

Сжатие работает аналогично растяжению. Вы можете установить разные режимы, если для элементов управления недостаточно места. ShrinkHorizontal, ShrinkVertical.

Отдельные ячейки

В приведенных выше примерах все элементы управления изменялись одинаково, каждый заполнял всю ячейку. Ячейка - это пространство в определенной строке и столбце. Обычно элемент управления заполняет все пространство ячейки. Это можно изменить с помощью свойств BorderSpacing.CellAlignHorizontal и BorderSpacing.CellAlignVertical.

Например, установите BorderSpacing.CellAlignHorizontal пятой кнопки в caCenter [и] вы получите следующее:

Autosize layout cellhorizontal cacenter.png

Существует четыре возможных значения для CellAlign Horizontal/CellAlign Vertical:

  • caFill: дочерний элемент управления заполняет всю ширину (высоту) ячейки
  • caCenter: дочерний элемент управления использует свою оптимальную ширину (высоту) и будет центрироваться в ячейке
  • caLeftTop: дочерний элемент управления использует свою оптимальную ширину (высоту) и выравнивается в ячейке слева
  • caRightBottom: дочерний элемент управления использует свою оптимальную ширину (высоту) и будет в ячейке выравниваться по правому краю

Autosize layout cellalign.png

Пользовательская разметка через OnResize/OnChangeBounds

Иногда разметка LCL недостаточно [оптимальна]. В приведенном ниже примере показан GroupBox1 со списком ListBox1 и Memo1. ListBox1 должен заполнить одну треть пространства, Memo1 - забрать все остальное.

Autosize onresize.png

Всякий раз, когда размер GroupBox изменяется, ListBox1.Width должен составлять одну треть. Для этого определите событие OnResize для GroupBox1:

procedure TForm1.GroupBox1Resize(Sender: TObject);
begin
  ListBox1.Width := GroupBox1.ClientWidth div 3;
end;

Общая ошибка: неправильное событие OnResize

Не помещайте весь свой код изменения размера [элементов управления] в событие Form OnResize. Событие Form OnResize вызывается только при изменении размера формы. Дочерние элементы управления (напр., GroupBox1) изменятся позже, поэтому GroupBox1.ClientWidth все еще [будет] иметь старое значение во время события FormResize. Вы должны использовать событие GroupBox1.OnResize, чтобы реагировать на изменения GroupBox1.ClientWidth.

Общая ошибка: Width вместо ClientWidth, AdjustClientRect

[Свойство] Width - это размер [элемента управления], включая рамку. [Свойство] ClientWidth - это внутренняя ширина [элемента управления] без рамки. Некоторые элементы управления, такие как TPanel, рисуют еще одну рамку. Потом вы используете AdjustClientRect. Тот же пример, но вместо GroupBox1 на Panel1 находится ListBox1:

procedure TForm1.Panel1Resize(Sender: TObject);
var 
  r: TRect;
begin
  r := Panel1.ClientRect;
  Panel1.AdjustClientRect(r);
  ListBox1.Width := (r.Right - r.Left) div 3;
end;



Пользовательские элементы управления

Когда вы пишете свой собственный элемент управления, вы можете переопределить и тонко настроить многие части автомасштаба LCL.

SetBounds, ChangeBounds, DoSetBounds

SetBounds вызывается, когда устанавливаются свойства Left, Top, Width, Height, BoundsRect, или пользователь вызывает его напрямую. SetBounds обновляет BaseBounds и BaseParentClientSize, которые используются [механизмом] привязки для сохранения размеров. Например, загрузка формы с TMemo и lfm[-файлом], содержащим [значения параметров] Left и Width [компонента] TMemo, вызывает [метод] SetBounds для TMemo два раза. Когда пользователь распахивает окно, SetBounds вызывается для формы, но не для Memo, сохраняя BaseBounds Memo. Если Memo привязан справа, [значение параметра] Width [компонента] Memo изменяется на основе [кода методов] BaseBounds и BaseParentClientSize. Имейте в виду, что данные aLeft, aTop, aWidth, aHeight могут быть недействительными и будут изменены LCL перед применением. Delphi чаще всего называет SetBounds. SetBounds вызывает ChangeBounds с KeepBase=false.

ChangeBounds вызывается всякий раз, когда позиция или размер элемента управления задаются либо с помощью свойств, либо с помощью [механизма разметки] LCL. SetBounds вызывает внутри [себя] ChangeBounds с KeepBase=false, в то время как [механизма разметки] LCL вызывает его с KeepBase=true. Переопределение этого в коде может изменить предпочтительный размер или изменить размеры других элементов управления. Имейте в виду, что данные aLeft, aTop, aWidth, aHeight могут быть недействительными и будут изменены LCL перед применением. Вы можете вызвать эту функцию.

DoSetBounds - это функция низкого уровня для установки private-переменных FLeft, FTop, FWidth, FHeight. Не вызывайте эту функцию, [потому что] только LCL вызывает ее. Она также обновляет FClientWidth и FClientHeight соответственно. Переопределите ее, чтобы обновить содержимое разметки элемента управления, например полосы прокрутки. Как всегда: не рисуйте здесь, но вызывайте Invalidate и рисуйте в OnPaint или переопределите Paint.

DoAdjustClientRectChange вызывается LCL и интерфейсом LCL, когда ClientRect изменился, а Width и Height сохранились.

WMSize существует для совместимости с Delphi/VCL. Он вызывается интерфейсом LCL при каждом изменении границ.

AdjustClientRect

Метод AdjustClientRect может быть переопределен вашими пользовательскими элементами управления и влияет на [свойства] Align, ChildSizing.Layout и AnchorSides. Это не влияет на значение Left, Top и не влияет на нормальный [механизм] привязки (например, установку).

Когда вы хотите нарисовать свою собственную рамку, тогда дочерние элементы управления должны быть выровнены в этой рамке. Например, TPanel рисует рамку и уменьшает клиентскую область, переопределяя метод AdjustClientRect:

  TCustomPanel = class(TCustomControl)
  ...
  protected
    ...
    procedure AdjustClientRect(var aRect: TRect); override;
  ...

procedure TCustomPanel.AdjustClientRect(var aRect: TRect);
var
  BevelSize: Integer;
begin
  inherited AdjustClientRect(aRect);

  BevelSize := BorderWidth;
  if (BevelOuter <> bvNone) then
    inc(BevelSize, BevelWidth);
  if (BevelInner <> bvNone) then
    inc(BevelSize, BevelWidth);

  InflateRect(aRect, -BevelSize, -BevelSize);
end;

AdjustClientRect и выравнивание

AdjustClientRect может использоваться для уменьшения клиентской области, используемой всеми операциями [автоматической установки] размера. Например, TPanel использует AdjustClientRect для уменьшения клиентской области посредством [изменения величины] зазора:

Adjustclientrect align.png

[Кнопка] Button1 на скриншоте была создана со [значением] Align=alClient. Также [был] задействован [свойство панели] ChildSizing.Layout.

Когда [дочерний элемент] привязывается к родительскому элементу через [свойство] AnchorSides, также используется параметр AdjustClientRect:

  Button1.AnchorParallel(akTop,0,Button1.Parent);

Верхний край Button1 привязан к верхнему краю клиентской области родителя. Если AdjustClientRect добавляет 3px к [значению] Top, Button1.Top будет 3px (3 плюс 0).

Собственный AutoSize

Когда параметру AutoSize установлено значение true, элемент управления должен быть изменен до оптимального размера, если это возможно.

Предпочтительный размер

Новый размер выбирается [механизмом] LCL через [метод] GetPreferredSize, который вызывает CalculatePreferredSize [и] который можно переопределить. Например, давайте опишем TQuadrat, который является [наследником] TShape, но его высота должна быть равна его ширине:

  TQuadrat = class(TShape)
  protected
    procedure CalculatePreferredSize(var PreferredWidth,
        PreferredHeight: integer; WithThemeSpace: Boolean); override;
  end;
...
procedure TQuadrat.CalculatePreferredSize(var PreferredWidth,
  PreferredHeight: integer; WithThemeSpace: Boolean);
begin
  PreferredHeight:=Width;
end;

Метод CalculatePreferredSize получает два переменных параметра: PreferredWidth и PreferredHeight. Они по умолчанию равны 0, что означает: нет оптимального размера, поэтому LCL не изменяет размер. Вышеупомянутая функция устанавливает [свойство] PreferredHeight в текущее [свойство] Width. Логический параметр WithThemeSpace устарел и всегда [равен] false.

Важно: [метод] CalculatePreferredSize не должен изменять границы или любое другое значение элемента управления, которое может инициировать [механизм] autosize. Это создаст [бесконечный] цикл.

Вычисление PreferredWidth/Height может быть дорогостоящей [операцией]. Поэтому LCL кэширует результат до тех пор, пока для элемента управления не будет вызвана [процедура] InvalidatePreferredSize. В нашем примере PreferredHeight зависит от [параметра] Width, поэтому мы должны [вызвать] перерисовку [элемента управления], когда изменяется [параметр] Width:

  TQuadrat = class(TShape)
  protected
    ...
    procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
  end;
...
procedure TQuadrat.DoSetBounds(ALeft, ATop, AWidth, AHeight: integer);
begin
  inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
  InvalidatePreferredSize;
  // Примечание: здесь [вызов метода] AdjustSize может быть опущен, поскольку LCL делает это после вызова DoSetBounds.
end;

LCL автоматически активирует [механизм] autosizing'а, когда границы изменяются, поэтому пример является полным.

По умолчанию TWinControl для реализации CalculatePreferredSize запрашивает виджетсет, который может вернуть оптимальную ширину и/или высоту. Каждый элемент управления может переопределять метод CalculatePreferredSize. Например, TImage переопределяет его и возвращает размер изображения. Если нет оптимальной ширины (высоты), возвращаемое значение [будет] равно 0, и LCL будет сохранять текущую [величину] Width (Height). Если 0 - допустимый размер для вашего контроля, вы должны присвоить флагу ControlStyle [значение] csAutoSize0x0 (ControlStyle:=ControlStyle+[csAutoSize0x0];). Примером может служить\элемент управления LCL TPanel.

AdjustSize

Когда предпочтительный размер зависит от нового свойства, то каждый раз, когда свойство изменяется, должен быть вызван [механизм] автоматического изменения размера. Например:

procedure TQuadrat.SetSubTitle(const AValue: string);
begin
  if FSubTitle = AValue then exit;
  FSubTitle := AValue;
  InvalidatePreferredSize;
  AdjustSize;
end;



Сокращение накладных расходов с помощью [методов] DisableAutoSizing, EnableAutoSizing

Начиная с [версии] Lazarus 0.9.29, существует новый алгоритм автоизменения размера, который уменьшает накладные расходы и допускает глубокие вложенные зависимости. До [версии] 0.9.28 [методы] DisableAlign/EnableAlign и Disable/EnableAutoSize работают только для одного элемента управления и его прямых дочерних контролов.

Каждый раз, когда вы меняете [какое-нибудь] свойство, LCL запускает [механизм] пересчета разметки:

Label1.Caption := 'A';  // первый перерасчет
Label2.Caption := 'B';  // второй перерасчет

Перерасчет будет возбуждать [механизм вызова] событий и отправки сообщений. Чтобы уменьшить накладные расходы, вы можете приостановить [механизм] автоизменения размера:

DisableAutoSizing;
try
  Label1.Caption := 'A';  // нет перерасчета
  Label2.Caption := 'B';  // нет перерасчета
finally
  EnableAutoSizing; // однократный перерасчет
end;

Вы должны уравновешивать вызовы Disable/EnableAutoSizing. Автоизменение размера начинается только тогда, когда вызывается EnableAutoSizing после соответствующего (ранее) [вызова] DisableAutoSizing.

Начиная с [версии Lazarus] 0.9.29, Disable/EnableAutoSize работает для всей формы. Это означает, что каждый вызов DisableAutoSizing приостанавливает автоизменение размера для всех элементов управления на этой форме. Если вы пишете свой собственный элемент управления, вы можете использовать следующее:

procedure TMyRadioGroup.DoSomething;
begin
  DisableAutoSizing;  // отключено автоизменение размера не только [для] TRadioGroup, но и [для] всей формы
  try
    // удаляем элементы ...
    // добавляем, тасуем элементы ...
    // меняем заголовки элементов ...
  finally
    EnableAutoSizing; // перерасчет
  end;
end;

К чему все это: вам не нужно [ни о чем] заботиться. Просто вызовите Disable/EnableAutoSizing.

Light bulb  Примечание: вот так неправильно:

Button1.DisableAutoSizing;
Label1.EnableAutoSizing; // неверно: каждый элемент управления имеет свой собственный 
                         //счетчик ссылок на автоизменение размера

DisableAutoSizing и границы формы

DisableAutoSizing имеет еще один полезный эффект при асинхронных менеджерах окон, которые вы [можете] встретить в системах Linux. Каждый раз, когда форма изменяет размер или перемещается, [ее] границы отправляются в widgetset (DoSendBoundsToInterface). Даже если форма не отображается, дескриптор изменяется. Менеджер окон зачастую рассматривает эти границы только в качестве предложения. У диспетчера окон есть своя логика, и часто используются только границы, переданные первыми. Второе, третье или дальнейшие перемещения могут быть проигнорированы. С помощью параметра DisableAutoSizing вы можете убедиться, что только последние границы отправляются в виджетсет, что делает границы формы более надежными [для отображения].



Прим.перев.: очевидно, имеется ввиду прерывистый механизм перерисовки границ окна, когда при перетаскивании его края мышью рисуется только рамка новой границы окна, а окончательная перерисовка происходит после отпускания кнопки мыши.




Пример: панель кнопок

В этом примере сочетаются несколько механизмов компоновки LCL для создания панели с тремя кнопками: кнопка Help слева и кнопки Ok и Cancel справа. Мы хотим, чтобы панель была внизу формы, заполняя всю [ее] ширину. Кнопки и панель автоматически изменяют размеры, чтобы соответствовать всем шрифтам и темам.

Шаг 1: Создайте панель и установите ее свойство Align в alBottom. Добавьте три TBitBtns.

Autosize example buttonpanel1.png

Установите в свойстве Kind BitBtns [соответственные] отображения глифов. Возможно, вам нужно будет установить свойство GlyphShowMode в gsmAlways[("отображать всегда")], чтобы увидеть их на своей платформе. Установите для свойства AutoSize [кнопок] BitBtn значение True, которое уменьшит/увеличит [ширину] кнопок для идеального заполнения [их] глифами и текстом. В зависимости от вашей темы и платформы вы можете заметить, что кнопки имеют разную высоту.

Autosize example buttonpanel2.png

Установите свойство Align ' кнопки справки в alLeft и установите для остальных двух кнопок свойство Align в alRight. Это увеличит кнопки по вертикали и переместит их в крайнее левое/правое. alLeft/alRight не влияют на ширину, поэтому кнопки используют свою предпочтительную ширину.

Autosize example buttonpanel3.png

Высота панели по-прежнему фиксирована. Теперь установите для панели свойство AutoSize в True. Панель теперь сжимается вертикально, чтобы соответствовать самой высокой кнопке.

Autosize example buttonpanel4.png

Кнопка Ok имеет короткий заголовок, поэтому кнопка очень маленькая. Установите для кнопки Constraints.MinWidth в значение 75. Теперь кнопка несколько расширится.

Autosize example buttonpanel5.png

Теперь добавьте некоторое пространство вокруг кнопок. Установите для панели ChildSizing.LeftTopSpacing/RightBottomSpacing/HorizontalSpacing в значение 6.

Autosize example buttonpanel6.png

Наконец, очистите Caption панели и установите ее 'BevelOuter в bvNone.

Autosize example buttonpanel7.png

Прокрутка

Некоторые элементы управления LCL, такие как TScrollBox, TForm' и TFrame, показывают полосы прокрутки, если дочерние элементы управления слишком велики, чтобы поместиться на scrollbox'е, форме или фрейме. Они наследуют это поведение от своего предка TScrollingWinControl.

Прокручиваемая логическая клиентская область элемента управления может быть больше, чем видимая клиентская область. Видимая клиентская область - это ClientRect. Она всегда начинается с [координат] 0,0 и его ширина и высота - это внутренняя область. Например, в TGroupBox - это размер области внутри фрейма. Итак, всегда верно следующее:

ClientWidth <= Width
ClientHeight <= Height

Логическая клиентская область определяется методом GetLogicalClientRect. По умолчанию она совпадает с ClientRect. Когда дочерний элемент управления привязан к правой стороне, он использует логическую клиентская область. TScrollingWinControl переопределяет этот метод и возвращает Range[(диапазон)] полос прокрутки, если [логическая клиентская область] больше, чем ClientRect. Range можно установить вручную или автоматически с помощью AutoScroll=true. Пример для AutoScroll=true:

Autoscroll all fit1.png

Верхняя кнопка имеет фиксированную ширину 200. Нижняя кнопка привязана к правой стороне панели. Поэтому дочерние элементы управления имеют предпочтительную ширину 200. Поскольку панель больше 200, логическая область клиента больше и нижняя кнопка расширяется.

Теперь панель сжата, так что ClientWidth становится меньше 200:

Autoscroll not fit1.png

Предпочтительная ширина по-прежнему равна 200, поэтому логического клиентская область теперь равна 200 и больше, чем видимая клиентская область. Нижняя кнопка имеет ширину 200, а на панели отображается горизонтальная полоса прокрутки.

Позиция прокрутки

Изменение положения полосы прокрутки не изменяет [значения] Left или Top любого дочернего элемента управления и не изменяет логическую клиентскую область, [а также] не влияет на автомасштабирование. Дочерние элементы управления лишь только виртуально перемещаются.

Прокрутка и автомасштаб

Когда AutoSize=true, LCL расширяет [родительский] элемент управления [так], чтобы разместить все его дочерние элементы управления, и никаких полос прокрутки не требуется. Если [родительский] элемент управления не может быть расширен, то (только) [тогда проявляется] вторичное действие AutoSize: перемещение дочерних элементов управления.

Пристыковка

Пристыковка использует описанные методы и свойства этой страницы, см. Docking.

Splitter

См. TSplitter.

TLabel.WordWrap

TLabel.WordWrap[(перенос слов)] изменяет поведение предпочтительного размера [компонента] label. WordWrap=true требует, чтобы [величина] Width [компонента] label была фиксированной, например, путем привязки левого и правого размера [компонента] label. Предпочтительная высота label затем вычисляется путем разбиения [своства] Caption на несколько строк.

Автоматическая настройка DPI и автоматическая настройка статической разметки

Исторически LCL использовался в основном для создания статической разметки, несмотря на огромное количество опций, которые Lazarus предлагает для гибкой разметки макетов, таких как Align, Anchors и т.д., которые описаны в остальной части этой статьи. Кроме того, он также исторически игнорировал DPI целевого [рабочего стола] и вместо этого использовал значения в пикселях для измерения свойств слева, сверху, ширины и высоты элементов управления. Для настольных платформ и Windows CE это работает нормально, но с появлением поддержки LCL для Android это больше нельзя игнорировать. Начиная с Lazarus 0.9.31, LCL может пересчитывать статическую разметку LCL в пикселях [на разметку] в виде гибкой сетки. Существует выбор нескольких режимов, [которые] позволяют пересчитывать значения пикселей как в абсолютных [величинах], так и в корректируемых для DPI, или как считающихся просто частью размера формы.

Важно отметить, что эти новые правила влияют только на элементы управления, которые расположены без выравнивания и только с большинством стандартных привязок.

В случае, когда значения будут корректироваться для DPI, появляется новое свойство: TCustomForm.DesignTimeDPI, которое должно хранить значение DPI системы, в которой была создана форма. Значения позиционирования будут расширены, когда DPI целевого [рабочего стола] будет больше, чем время DPI времени разработки или уменьшено в противном случае. Обычное значение DPI для рабочего стола - 96, и это значение, заданное по умолчанию.

property DesignTimeDPI: Integer read FDesignTimeDPI write FDesignTimeDPI;

Способ настройки разметки можно контролировать с помощью свойства TApplication.LayoutAdjustmentPolicy

  TLayoutAdjustmentPolicy = (
    lapDefault,     // Зависимость от виджетсета
    lapFixedLayout, // Фиксированная абсолютная разметка на всех платформах
    lapAutoAdjustWithoutHorizontalScrolling, // Это используется платформой для смартфонов,
                                             // ось x растягивается, чтобы заполнить экран и
                                             // y масштабируется, чтобы соответствовать DPI
    lapAutoAdjustForDPI // Для рабочих столов с использованием High DPI, x и y масштабируются соответственно DPI
  );

Следующие новые методы в TControl позволяют [задать] принудительную автонастройку разметки в конкретном контроле и во всех его дочерних элементах, или контролировать, как реагируют на это отдельные потомки TControl:

TControl = class
public
...
    procedure AutoAdjustLayout(AMode: TLayoutAdjustmentPolicy;
      const AFromDPI, AToDPI, AOldFormWidth, ANewFormWidth: Integer); virtual;
    function ShouldAutoAdjustLeftAndTop: Boolean; virtual;
    function ShouldAutoAdjustWidthAndHeight: Boolean; virtual;

LCL-CustomDrawn-Android будет вызывать AutoAdjustLayout, например, когда экран вращается.

Подробнее

Многие элементы управления переопределяют TControl.DoAutoSize для выполнения фактического автомасштабирования.

ВАЖНО: Многие элементы управления Delphi переопределяют этот метод, и многие вызывают этот метод напрямую после установки некоторых свойств.

Во время создания дескриптора не все интерфейсы могут создавать полные Device Contexts[(контексты устройств)], которые необходимы для вычисления таких вещей, как размер текста.

Вот почему вы всегда должны называть AdjustSize вместо DoAutoSize.

TControl.AdjustSize вызывает DoAutoSize умным способом.

Во время загрузки и создания дескриптора вызовы задерживаются.

Этот метод изначально делает то же самое, что и TWinControl.DoAutoSize. Но поскольку DoAutoSize обычно переопределяется компонентами-потомками, нецелесообразно выполнять все проверки, которые могут привести к слишком большим издержкам. Чтобы уменьшить это, LCL вызывает AdjustSize.

При установке AutoSize=true LCL автомасштабирует элемент управления по ширине и высоте. Это одна из самых сложных частей LCL, потому что результат зависит от почти сотен свойств. Начнем с простого:

LCL будет только автомасштабировать Width (Height), если [это свойство] свободно для изменения величины. Другими словами - ширина не автомасштабируется, если:

  • левая и правая стороны привязаны. Вы можете привязать стороны с [помощью] свойства Anchors или установить свойство Align в alTop, alBottom или alClient.
  • [параметр] Width ограничен [значением] свойства Constraints. [Свойство] Constraints также может быть переопределено виджетсетом. Например, winapi не позволяет изменять размер выпадающего списка. Или gtk widgetset не позволяет изменять ширину вертикальной полосы прокрутки.

То же [справедливо и для свойства] Height.

Новый размер рассчитывается protected-методом TControl.CalculatePreferredSize. Этот метод запрашивает виджетсет для [получения] подходящих Width и Height. Например, TButton имеет предпочтительные ширину и высоту. TComboBox имеет только предпочтительную высоту. [У него] предпочтительная ширина возвращается как 0, и поэтому LCL не автомасштабирует ширину - [LCL] сохраняет ширину неизменной. Наконец, у TMemo нет предпочтительной ширины или высоты. Поэтому [параметр] AutoSize не влияет на TMemo.

Некоторые элементы управления перекрывают этот метод. Например, потомки TGraphicControl, такие как TLabel, не имеют дескриптора окна и поэтому не могут запрашивать виджетсет. Они должны сами рассчитать их предпочтительную ширину и высоту.

Виджетсеты должны переопределять метод GetPreferredSize для каждого класса виджетов, который имеет предпочтительный размер (ширина или высота, или оба).

Parent.AutoSize

Выше описанное [дает] простое объяснение. Реальный алгоритм [функционально] предусматривает гораздо больше возможностей и, следовательно, гораздо более сложен.

Свойства / Методы

  • Left
  • Top

Если Parent<>nil, то [значения] Left, Top - это расстояние в пикселях до верхнего левого пикселя клиентской области родителя (не прокручивается). Помните, что клиентская область - это всегда [область] без рамки и полосы прокрутки родителя. Для пользователей Delphi: некоторые элементы управления VCL, такие как TGroupbox, определяют клиентскую область как весь элемент управления, включая рамку, а некоторые нет - LCL же более последователен, поэтому Delphi [с ним] несовместим. Left и Top могут иметь отрицательные [значения] или [быть] больше, чем область клиента. Некоторые виджетсеты определяют минимум/максимум где-то около 10000[px] или более.

Когда клиентская область прокручивается, Left и Top остаются неизменными.

Во время изменения размера/перемещения [элемента управления] Left и Top не всегда синхронизируются с координатами дескриптора объекта.

Если Parent=nil, тогда [значения] Left, Top зависят от виджетсета и диспетчера окон. До [версии] Lazarus 0.9.25 это обычно были координаты экрана верхне-левой части клиентской области формы. Это несовместимо с Delphi. Планируется изменить это [поведение] на Left, Top окна.

Подсказка: Каждый раз, когда вы изменяете Left и Top, LCL мгновенно приходит в движение и перекомпонует весь макет. Если вы хотите изменить Left и Top, используйте взамен:

with Button1 do
  SetBounds(NewLeft, NewTop, Width, Height);


  • Width
  • Height

Размер в пикселях не должен быть отрицательным, и большинство виджетсетов не допускают Width=0 и/или Height=0. Некоторые элементы управления на некоторых платформах определяют наибольшее минимальное ограничение в Constraints.MinInterfaceWidth/Height. Вместо того, чтобы изменять размер элемента управления в Width=0 и/или Height=0, установите Visible=false или Parent=nil. Во время изменения размера/перемещения [свойства] Width и Height не всегда синхронизируются с размером дескриптора объекта.

  • BoundsRect

Аналогично Bounds(Left, Top, Width, Height).

Обычная ошибка новичка:

BoundsRect.Left := 3; // НЕПРАВИЛЬНО: обычная ошибка новичка


Это не [оказывает никакого] влияния, потому что чтение BoundsRect является функцией. Она создает временный TRect в стеке. Вышеупомянутое те же, что и

var
  r: TRect;
begin
  r := BoundsRect; // получаем границы
  r.Left := 3;  // изменяем значение в стеке
end;  // нет изменений


  • ClientRect

Left и Top всегда равны 0,0. [Свойства] Width и Height - это видимый размер клиентской области в пикселях. Помните, что клиентская область - это [то, что] без рамки и без полос прокрутки. В прокручиваемой клиентской области логическая клиентская область может быть больше видимой.

  • ClientOrigin

Возвращает экранную позицию верхне-левой координаты 0,0 клиентской области. Обратите внимание, что это значение является позицией, сохраненной в интерфейсе, и не всегда синхронизируется с LCL. Когда элемент управления перемещается, LCL устанавливает границы в нужную позицию и отправляет сообщение [о] перемещении в интерфейс. Интерфейс обрабатывает [сообщения о] перемещениях сразу или по очереди.

  • LCLIntf.GetClientBounds

Возвращает клиентские границы элемента управления. Аналогичен ClientRect, но Left и Top - это расстояния в пикселах до левого и верхнего краев элемента управления. Например, в TGroupBox [параметры] Left, Top являются шириной и высотой левой и верхней границ рамки. Прокрутка не влияет на GetClientBounds.

  • LCLIntf.GetWindowRect

После вызова [этой функции] ARect будет областью элемента управления в координатах экрана. Это означает, что Left и Top будут экранной координатой верхне-левого пикселя Дескриптора объекта, а [значения] Right и Bottom будут экранной координатой нижне-правого пиксела.

  • FBaseBoundsLock: integer

Увеличивается/уменьшается [методами] LockBaseBounds/UnlockBaseBounds. Используется для сохранения [поля] FBaseBounds во время вызова SetBounds.

  • FBaseParentClientSize: TPoint

Размер Parent.ClientRect действителен для FBaseBounds. [Поля] FBaseBounds и FBaseParentClientSize используются для вычисления расстояния для [параметра выравнивания] akRight (aBBottom). Когда размер родителя изменяется, LCL знает, какое расстояние сохранить.

  • FBoundsRectForNewParent: TRect

При смене родителя элемента управления Дескриптор [объекта] создается [заново], и многое может случиться. Особенно этот процесс ненадежен для пристыкованных форм. Поэтому BoundsRect сохраняется. VCL использует аналогичные механизм.

  • fLastAlignedBounds: TRect

Для получения пояснения см. TControl.SetAlignedBounds. Коротко: он останавливает некоторые циклы между интерфейсом и автомасштабированием в LCL.

  • FLastChangebounds: TRect

Используется для остановки вызова ChangeBounds с одинаковыми координатами. Это случается очень часто.

  • FLastDoChangeBounds: TRect

Используется, чтобы избежать вызова OnChangeBounds с теми же координатами. Это подавляет пользовательскую настройку автомасштабирования.

  • FLastResizeClientHeight: integer
  • FLastResizeClientWidth: integer
  • FLastResizeHeight: integer
  • FLastResizeWidth: integer

Используется, чтобы избежать вызова OnResize с теми же координатами. Это подавляет пользовательскую настройку автомасштабирования.

  • FLoadedClientSize: TPoint

Во время загрузки многие вещи задерживаются, а многие вещи устанавливаются в неправильном порядке и ухудшаются. Вот почему сохраняется и вновь вызывается SetClientWidth/SetClientHeight в конце загрузки. Таким образом, LCL может восстанавливать размеры (напр., при akRight), используемые во время проектирование.

  • FReadBounds: TRect

Аналогично FLoadedClientSiz, но для SetLeft, SetTop, SetWidth, SetHeight.

  • procedure SetBoundsRectForNewParent(const AValue: TRect);

Используется для установки FBoundsRectForNewParent. См. выше.

  • procedure SetAlignedBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;

Как SetBounds, но без изменения размеров по умолчанию.

  • procedure SetInitialBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;<//tt>

"Умная" версия SetBounds, уменьшающая накладные расходы при создании и загрузке.

  • procedure UpdateBaseBounds(StoreBounds, StoreParentClientSize, UseLoadedValues: boolean); virtual;

Фиксирует текущие границы базовых границ.

  • procedure SetClientHeight(Value: Integer);
  • procedure SetClientSize(Value: TPoint);
  • procedure SetClientWidth(Value: Integer);

Существует также для совместимости с Delphi. Изменяет размер элемента управления, чтобы получить желаемый размер ClientRect.

  • procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;

Это внутренний SetBounds. Применяет ограничения, обновляет базовые границы, вызывает OnChangeBound, OnResize, блокирует границы.

  • procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); virtual;

Этот [метод] действительно устанавливает частные private-переменные FLeft, FTop, FWidth, FHeight.

  • procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;

Это стандартная процедура, переопределяющая многие элементы управления Delphi. Также переопределяет TWinControl.

    • игнорирует вызовы, когда границы заблокированы
    • блокирует FBoundsRealized, чтобы избежать накладных расходов на интерфейс во время автомасштабирования. ChangeBounds таким образом не блокируется.
  • Function GetClientOrigin: TPoint; virtual;

Координаты экрана Left, Top клиентской области.

  • Function GetClientRect: TRect; virtual;

Размер клиентской области. (всегда Left=0, Top=0)

  • Function GetScrolledClientRect: TRect; virtual;

Видимая клиентская область ClientRect.

  • function GetChildsRect(Scrolled: boolean): TRect; virtual;

Возвращает клиентский прямоугольник относительно Left, Top элемента управления. Если [свойство] Scrolled [имеет значение] true, прямоугольник перемещается текущими значениями прокрутки (например, см. TScrollingWincontrol).

  • function GetClientScrollOffset: TPoint; virtual;

Возвращает смещение прокрутки клиентской области.

  • function GetControlOrigin: TPoint; virtual;

Возвращает экранные координаты верхне-левой координаты 0,0 области элемента управления (верхне-левый пиксель элемента управления на экране). Обратите внимание, что это значение является позицией, сохраненной в интерфейсе, и не всегда синхронизируется с LCL. Когда элемент управления перемещается, LCL устанавливает границы в желаемую позицию и отправляет сообщение о перемещении в интерфейс. [А уж] интерфейс обрабатывает перемещаемый дескриптер сразу или в [порядке] очереди.

ЧаВо

Почему [свойство] AutoSize не работает в дизайнере должным образом?

В дизайнере элементы управления можно перемещать, и свойства могут быть установлены практически в любом порядке. Чтобы разрешать это и избегать возможных конфликтов, [свойство] AutoSizing не обновляется при каждом изменении во время разработки.

Почему TForm.AutoSize не работает, когда что-то меняется?

См. Автомасштаб и формы

Нужно ли мне вызывать Application.ProcessMessages при создании большого количества элементов управления?

Application.ProcessMessages вызывается LCL автоматически после каждого сообщения (например, после каждого события, такого как OnClick). Вызов его сам по себе необходим только в том случае, если изменения должны немедленно стать видимыми пользователю. Например:

procedure TFrom.Button1Click(Sender: TObject);
begin
  // изменяем ширину элемента управления
  Button1.Width := Button1.Width + 10;
  // применяем все необходимые изменения и перерисовываем кнопку
  Application.ProcessMessages;
  // делаем много вещей, которые занимают много времени
  ...
  // после выхода из OnClick LCL автоматически обрабатывает сообщения
end;

При включении привязки во время исполнения [приложения] элементы управления изменяют размеры, но не используют текущие значения. Почему?

akBottom означает: сохранить расстояние до нижней части родителя. Зазоры для удержания определяются основными границами. Они устанавливаются в режиме разработки или во время исполнения вызовом [методов] SetBounds или UpdateBaseBounds.

Например: TListBox (Anchors=[akLeft,aTop]) при проектировании имеет нижний зазор в 100 пикселей. И кнопку для включения/выключения [значения] akBottom TListBox'а. Теперь запустите приложение и нажмите кнопку, чтобы включить akBottom. 100-пиксельное расстояние будет активировано, потому что это был последний раз, когда программист определил базовые границы TListBox. Все остальные изменения были сделаны LCL и не имеют значения. Основные границы[, заданные] программистом определяют правила. Вы можете изменить размер формы, но 100 пикселей будет сохранено. Чтобы использовать текущие границы в качестве базовых, используйте:

ListBox1.UpdateBaseBounds(true, true, false);
ListBox1.Anchors := ListBox1.Anchors + [akBottom];

Установка привязки не вызывает автоматически [вызов метода] UpdateBaseBounds, потому что это само по себе может уничтожить возможность изменения свойств.

Изменение размера столбцов stringgrid в событии OnResize формы не работает

[Событие] OnResize формы запускается, когда изменяются [значения] Width, Height, ClientWidth или ClientHeight формы. Это само по себе не зависит [непосредственно] от TStringGrid. Конечно, часто бывает, что и форма, и TStringGrid изменяют размеры. Это означает[, что в таких случаях] использование [события] OnResize формы часто будет работать, но не всегда. Ярким примером [того, что использование OnResize формы] всегда терпит неудачу, является [случай], когда тема изменена, и у вас есть TStringGrid[, лежащий] в TGroupBox на TForm. Когда тема меняется, размеры формы сохраняются, поэтому никакого [события] OnResize формы не запускается. Но меняется [соответственно теме] TGroupBox, поэтому TStringGrid должен быть изменен.

Решение: используйте [событие] OnResize TStringGrid'а.

Почему TForm.Width равен TForm.ClientWidth?

Примечание Mattias'а:

"Есть исторические и технические причины.

Для форм без родителя Clientwidth равен Width, поскольку реальная ширина, включая рамку, не была доступна в Linux десять лет назад (по крайней мере, не достоверно для разных оконных менеджеров). Я не тестировал, но слышал, что теперь это возможно с gtk2. Основная проблема заключается в автомасштабировании, потому что для этого нужны размеры рамки до того, как форма будет отображена на экране. Возможно, [размер рамки] доступен только после [наступления] события, а это значит, что вам нужно подождать, что означает проблему для ShowModal. Изменив это, вы нарушите совместимость с большим количеством существующего кода LCL/ru, но для этого мы добавили LCLVersion в файлы lfm.

Существует новое определение компилятора LCLRealFormBounds в Lazarus trunk 1.7, которое позволяет использовать реальный размер для формы. Чтобы использовать его, просто скомпилируйте свое приложение с помощью LCLRealFormBounds ON. Пока что поддерживается только widgetset win32.

Для всех остальных элементов управления применяются правила ClientWidth<=Width. Width - это ClientWidth плюс рамка виджета. Вопрос в том, принадлежат ли полосы прокрутки рамке. Я бы сказал "да", и это было реализовано таким образом некоторое время назад. Видимо, это изменилось. См. Текущую проблему с курсором в synedit."

Я получаю бесконечный цикл / Как отладить автомасштабирование?

Вот некоторые примечания, что другие пользователи сделали неправильно и как найти выход:

Отличия от Delphi

Для пользователей Delphi: пожалуйста, прочитайте: Отличия от Delphi

Переопределение метода LCL и запуск пересчета

Вы переопределяете метод и просите LCL пересчитать снова, даже если ничего не изменилось. Проверьте настройки AdjustSize, Realign, AlignControls, InvalidatePreferredSize. Например:

procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
begin
  // Это создаст бесконечный цикл
  InvalidatePreferredSize;

  // Это также создаст бесконечный цикл:
  OtherComponent.Left:=10;
  OtherComponent.Left:=20;

  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;

Объяснение: метод SetBounds вызывается часто, даже ничего не меняя. Например, так будет делать "Left:=30;".

Решение: отслеживайте изменения:

procedure TMainForm.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
begin
  if (Left <> ALeft) or (Top <> ATop) or (Width <> AWidth) or (Height <> AHeight) then
    InvalidatePreferredSize;
  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;

TWinControl.AlignControls

procedure AlignControls(aControl: TControl; var aRect: TRect); override;

AlignControls перемещает и упорядочивает все дочерние элементы управления. Реализация LCL игнорирует элементы управления с помощью Align=alCustom.

Параметр aControl: TControl поддерживается для совместимости с VCL. LCL всегда возвращает nil. Он дает приоритет aControl при применении свойства Align. Если у вас есть, например, два элемента управления A,B со [значением] Align=alLeft, то [элемент управления, который будет] нижним слева расположится левее [другого]. Если оба имеют одинаковые [значения] Left, [то] приоритетнее [элемент в] порядке создания. Теперь представьте, что вы хотите переключить оба элемента управления A, B в дизайнере. Вы перетащите B влево. Это приведет к установке [значения] B.Left в 0. Теперь AlignControls запускается и находит[, что у обоих элементов управления значения] A.Left=0 и B.Left=0. В обычном [случае] A [по расположению окажется в] приоритете. Чтобы [приоритетнее оказался элемент управления] B, VCL вызовет AlignControls(B,r). Таким образом, aControl является последним перемещенным. В отличие от VCL, LCL позволяет комбинировать несколько изменений разметки без перерасчета на каждом шагу. LCL отслеживает последние перемещенные элементы управления в TWinControl.fAlignControls и применяет порядок в TWinControl.CreateControlAlignList. Параметр aControl всегда равен nil.

Смотри TWinControl.CreateControlAlignList.

OnResize/OnChangeBounds конфликтует со свойствами LCL

Вы устанавливаете границы, которые ущемляют свойства LCL. Например, по умолчанию TLabel.AutoSize [имеет значение] true. Если вы определяете Label1.Width в событии OnResize, LCL будет [запускать] пересчет, изменяя размер Label1, и снова вызывать OnResize. Запустите приложение в отладчике и воспроизведите ошибку. Когда оно войдет в [бесконечный] цикл, приостановите приложение и смотрите стек вызовов. Как вы видите, одно из ваших событий или ваших методов начинают искать там. Например:

procedure TMainForm.FormResize(Sender: TObject);
begin
  // если Button1 привязан или AutoSize=true, то следующее может создать бесконечный цикл:
  Button1.Width:=100;
end;

Ошибка интерфейса LCL, пользовательский виджет

Иногда интерфейс LCL или ваш пользовательский элемент управления имеет ошибку и отменяет границы LCL. Скомпилируйте LCL с [опцией] -dVerboseIntfSizing. Это запишет связь между LCL и интерфейсом LCL. Если виджет не допускает свободное изменение размера, он должен сказать [об этом] LCL через Constraints[(ограничения)]. Поищите SetInterfaceConstraints в различных интерфейсах LCL и TWSControlClass.ConstraintWidth/Height.

alCustom

Вы используете alCustom. В ранних версиях Lazarus это было реализовано только наполовину, но некоторые даровитые программисты использовали его для создания некоторых специальных эффектов. Теперь это реализовано, и ваша программа больше не работает. Пожалуйста, см. здесь, что alCustom делает: alCustom.

См. также