Anchor Docking/ru

From Free Pascal wiki

English (en) русский (ru)

Про стыковку вообще см. Docking.

Contents

Обзор

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

Пристыковка с привязкой реализована, начиная с версии 0.9.29, в пакете anchordocking.lpk. Он прост в использовании и предоставляет множество функций и опций, недоступных в более ранних установочных пакетах.

Пример кода вы найдете здесь: components/anchordocking/miniide/miniide1.lpi

Это означает, что более ранние модули TLazDockingManager и LDockCtrl устарели и далее поддерживаться не будут.

Характеристики

  • Перетаскивание и стыковка: добавлены заголовки, которые можно перетаскивать с помощью мыши на стыкуемые элементы управления . Прямоугольники предварительного просмотра покажут, где и как закреплен элемент управления.
  • Любой макет: с помощью привязок LCL возможна практически любая компоновка. Вы можете пристыковать [компонент] влево, вправо, сверху, снизу, внутри или снаружи или в виде страницы, как [это сделано] в TPageControl. Вы можете расширять пристыкованные элементы управления через всплывающее меню. Нет необходимости расстыковывать весь макет.
  • То, что вы видите, как это структурировано: тут нет скрытых панелей для выравнивания элементов управления в строках и столбцах. Пристыковка с привязкой гарантирует, что формы не будут перекрываться.
  • Сплиттеры автоматически вставляются между пристыкованными формами для [получения возможности] изменения размера.
  • Пристыковка страницы: формы можно стыковывать не только влево/вправо/сверху/снизу, но и внутри страницы. TPageControl автоматически создается для естественного внешнего вида. Страница также может содержать произвольные пристыкованные формы, включая сопутствующие пристыкованные формы, допускающие вложенные страницы и макеты. Когда страница отстыкована от pagecontrol, она автоматически удаляется. Вы можете таскать и бросать вкладки или использовать всплывающее меню для перемещения страниц.
  • Простота использования: с помощью одной строки кода вы можете сделать форму или элемент управления стыкуемыми. Просто дайте им уникальные имена.
  • Не только формы, но и любой TWinControl может быть сделан стыкуемым.
  • Можно сохранять/загружать макеты: информация о макете сохраняется для каждого пристыкованного элемента управления, а старые файлы макетов будут работать [по-прежнему], даже если приложение получит больше пристыкованных элементов управления или некоторые из них будут удалены. Информация хранится в абстрактном классе LCL TConfigStorage. Таким образом, вы можете использовать, например, TXMLConfigStorage для хранения макетов в XML-файлах, или вы можете создать собственное хранилище для хранения его в любом месте.
  • Каждая пристыкованная форма помещается в стыковочный узел, предоставляя необязательный заголовок. Заголовок показывает название пристыкованной формы и содержит кнопку закрытия. Вы можете перетащить заголовок, чтобы перетащить форму и отстыковать ее или пристыковать в другой позиции. Заголовок может находиться на любой из четырех сторон и по умолчанию автоматически перемещается на меньшую сторону, чтобы сэкономить место. Вы можете настроить и это. Заголовок показывает настраиваемую подсказку, позволяющую читать длинные надписи.
  • При изменении размера стыковочного узла дочерние узлы масштабируются автоматически. Вы можете отключить это.
  • Сохранение размеров форм: например, при стыковке формы к левой стороне стыковочного узла ширина пристыкованной формы сохраняется. То же самое справедливо для других сторон, а также при отстыковке.
  • Уменьшение мерцания: при восстановлении предпринимается попытка повторно использовать существующие узлы и разделители, чтобы уменьшить создание и мерцание форм, и сохранить Z-порядок(порядок наложения) форм. Это позволяет быстро переключаться между макетами.
  • Всплывающее меню заголовка:
    • блокировать/разблокировать (отключить перетаскивание)
    • положение заголовка (авто, слева, сверху, справа, снизу), это сохраняется/восстанавливается вместе с макетом
    • объединить (например, после перемещения стыковочного узла страницы внутрь макета)
    • отстыковать (требуется, если нет места для отстыковки на экране)
    • увеличить сторону слева, сверху, справа, снизу
    • закрыть
    • настройки
  • Всплывающее меню страницы:
    • блокировать/разблокировать (отключить перетаскивание)
    • отстыковать (требуется, если нет места для отстыковки на экране)
    • положение вкладки для управления страницей (сверху, снизу, слева, справа), это сохраняется/восстанавливается вместе с макетом
    • переместить страницу влево, вправо, в крайнее левое положение, в крайнее правое положение
    • закрыть
    • настройки
  • Формы могут создавать стыковочные узлы. Тогда они могут пристыковываться к одной из сторон. Но их нельзя пристыковать к себе.
  • Кнопка закрытия автоматически сохраняет макет
  • Мощные функции для изменения макета. Вы можете использовать Drag&Drop, чтобы переместить форму, а также вы можете отстыковать и пристыковать ее за один раз. Есть функции для увеличения форм и сжатия других. Эти функции также доступны через всплывающее меню заголовка. См. ниже.
  • Существует пакет IDE, который позволяет сделать стыкуемыми [окна интерфейса] IDE Lazarus. Он называется anchordockingdsgn.lpk. Убедитесь, что вы устанавливаете только один пакетдля пристыковки. Не устанавливайте easydockmgr одновременно!

Запланированное

  • Пакет времени разработки: добавление всех файлов макета в меню
  • Простой способ сделать формы прикрепляемыми во время разработки (то есть без написания кода)
  • Кнопка сворачивания и скрытия
  • При показе снова: восстановить макет по умолчанию
  • Кнопка закрытия для страниц
  • Реализовать автоматическое слияние меню в LCL (когда две формы с основными меню состыкованы).

Использование

Быстрый старт

Добавьте пакет AnchorDocking к требуемым пакетам в инспекторе проектов.

Затем добавьте модуль AnchorDocking в раздел uses вашего основного модуля (модуль вашей основной формы).

Добавьте в событие OnCreate вашей основной формы:

  DockMaster.MakeDockSite(Self,[akBottom],admrpChild);

Для других стыкуемых форм замените все вызовы Show и ShowOnTop на

  DockMaster.MakeDockable(Form1,true,true);

Для других стыкуемых форм замените все вызовы Visible:=true на

  DockMaster.MakeDockable(Form1,true);

Удалите или закомментируйте все вызовы Hide, Visible:=false, WindowState:=.

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

  • Ваш проект должен использовать пакет AnchorDocking.
  • Все стыкуемые формы должны показываться с помощью MakeDockable или MakeDockSite. Не используйте Show, BringToFront, ShowOnTop, Visible:=true. Конечно же, у вас может быть несколько не пристыковывающихся форм, таких как всплывающие подсказки или заставки.
  • Все стыкуемые формы должны иметь свободно изменяемый размер, это означает, что нет ограничений, нет BorderStyle=bsDialog.
  • Нет другой системы пристыковки. AnchorDocking несовместим с EasyDockMgr.

Превращение форм в стыкуемые

Есть два способа сделать форму стыкуемой. Вы можете использовать DockMaster.MakeDockable, чтобы пристегнуть форму к док-узлу(стыковочному узлу). Тогда ваша форма может пристыковывать и быть стыкуемой совершенно свободно. Вы будете использовать этот способ для большей части ваших форм, за исключением MainForm, потому что это поддерживается для MainForm только в gtk2 и qt. Второй способ - использовать DockMaster.MakeDockSite. Форма может пристыковывать другие узлы, но не может быть пристыкована сама. Вы можете использовать MakeDockSite для MainForm. Для большинства других форм вы, вероятно, захотите использовать это:

// показываем YourForm
// если это еще не сделано, пристегиваем форму к док-узлу
DockMaster.MakeDockable(YourForm);

Вот несколько примеров того, как форма может быть пристыкована с помощью DockMaster.MakeDockable:

Top Top

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

Пример: miniide1

Пример можно найти в lazarus/components/anchordocking/miniide/miniide1.lpi. Он имеет mainform в модуле unit1.pas с главным меню, которая работает как док-узел, и несколькими формами, которые можно пристыковать.

Anchordocking miniide1.png

Превращение главной формы в стыковочный узел

В TMainIDE.FormCreate основная форма MainIDE превращается в стыковочный узел:

DockMaster.MakeDockSite(Self,[akBottom],admrpChild);

Параметр [akBottom] позволяет пристыковывать другие узлы в нижней части MainIDE. Параметр admrpChild сообщает DockMaster, что при расширении MainIDE дополнительное пространство распределяется между закрепленными узлами.

Когда пользователь пристыковывает узел в нижней части MainIDE, узел помещается на MainIDE (Site.Parent:=MainIDE) с выравниванием Site.Align=alBottom. Другие элементы управления на MainIDE должны быть с ним совместимы. Например, MainIDE имеет BtnPanel с выравниванием Align=alLeft и TNoteBook с выравниванием Align=alClient. См. здесь, чтобы увидеть, как работает Align.

DockMaster автоматически добавляет сплиттер:

Anchordocking miniide dockedse1.png

Как только стыкуемая форма прикрепляется, ее заголовок отображается в заголовке дока.

Требования к настраиваемому стыковочному узлу

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

  • AutoSize=true может привести к бесконечному циклу. Отключите это свойство или переопределите DoAutoSize/CalculatePreferredSize и будьте особенно внимательны.
  • Ограничения: DockMaster очищает максимум ограничений и восстанавливает их при отстыковке.
  • Дочерние элементы управления, привязанные к выровненному узлу, могут перекрываться. См. здесь, как работает Align.
  • ChildSizing: свойства зазоров, таких как LeftRightSpacing, TopBottomSpacing, могут мешать стыковочному макету.

Процедура создания всех других форм по имени

MainIDE задает событие DockMaster.OnCreateControl, чтобы позволяет DockMaster создавать формы по имени. Это необходимо для восстановления макетов.

DockMaster.OnCreateControl:=@DockMasterCreateControl;
procedure TMainIDE.DockMasterCreateControl(Sender: TObject; aName: string; var
  AControl: TControl; DoDisableAutoSizing: boolean);

  procedure CreateForm(Caption: string; NewBounds: TRect);
  begin
    AControl:=CreateSimpleForm(aName,Caption,NewBounds,DoDisableAutoSizing);
  end;

begin
  // сначала проверяем существование формы
  // LCL Screen содержит список всех существующих форм
  // Примечание: помните, что LCL допускает в качестве имен форм только стандартные
  // Паскаль идентификаторы и сравнивает их без учета регистра
  AControl:=Screen.FindForm(aName);
  if AControl<>nil then begin
    // если он уже существует, просто отключите автоматическое изменение размера, если требуется
    if DoDisableAutoSizing then
      AControl.DisableAutoSizing;
    exit;
  end;
  // если форма еще не существует, создаем ее
  if aName='CodeExplorer' then
    CreateForm('Code Explorer',Bounds(700,230,100,250))
  ...
  else if aName='DebugOutput' then
    CreateForm('Debug Output',Bounds(400,400,350,150));
end;

Создать форму можно очень просто:

MyForm:=TMyForm.Create(Self);
if DoDisableAutoSizing then
  MyForm.DisableAutoSizing;

Но, конечно, вы можете поместить туда все виды кода инициализации.

DisableAutoSizing уменьшает мерцание. Убедитесь, что свойство Visible формы установлено в значение false.

Не забудьте вызвать DisableAutoSizing для формы, если для параметра DoDisableAutoSizing установлено значение true, поскольку вызовы Disable- и EnableAutosizing должны быть сбалансированы. Если вы пропустите DisableAutosizing, LCL создаст исключение позже:

TControl.EnableAutoSizing SourceEditor1:TSimpleForm: missing DisableAutoSizing

MissingDisableAutoSizing.png

Если вы слишком часто вызываете DisableAutoSizing, ваши формы не будут отображаться и/или не будут должным образом изменять размер, поскольку LCL будет ожидать вызова EnableAutoSizing, который так никогда и не поступит.

Отображение форм

Раньше, для отображения формы, вы, вероятно, использовали что-то вроде MyForm.Show. Вместо этого вы должны теперь использовать

DockMaster.MakeDockable(MyForm);

Это "обернет" MyForm в стыковочный узел и покажет его. Узел достаточно "умен", чтобы выяснить, что форма уже "обернута" в него.

Если вы установили событие DockMaster.OnCreateControl, вы можете использовать это:

DockMaster.ShowControl('MyForm',true);

Пристыковка вручную, программно

Используйте процедуру DockMaster.ManualDock, чтобы пристыковать узел к другому.

procedure ManualDock(SrcSite, TargetSite: TAnchorDockHostSite; Align: TAlign; TargetControl: TControl = nil);
  • SrcSite - это узел для стыковки. Если SrcSite был пристыкован, он будет отстыкован первым.
  • TargetSite - это ["родительский"] узел, у которого SrcSite будет пристыкован либо внутри, либо как соседнее окно.
  • TargetControl - указывает, в виде какого окна будет пристыкована форма: как соседнее (=nil), внутри соседа (=TargetSide) или перед страницей (=TAnchorDockPage).

Отстыковка вручную, программно

Используйте процедуру DockMaster.ManualFloat, чтобы отсоединить узел от его соседей и создать плавающую форму верхнего уровня. Встроенный элемент управления остается встроенным в TAnchorDockHostSite.

 procedure ManualFloat(AControl: TControl);

В качестве параметра можно указать TAnchorDockHostSite или элемент управления, встроенный в TAnchorDockHostSite (например, форму, которая была пристыкована с помощью MakeDockable). Узел будет размещен в том же месте экрана.

Сохранение макета

DockMaster позволяет сохранять текущий макет в TConfigStorage. В примере miniide используется версия xml:

procedure TMainIDE.SaveLayout(Filename: string);
var
  XMLConfig: TXMLConfigStorage;
begin
  try
    // создаем новый XML-файл конфигурации
    XMLConfig:=TXMLConfigStorage.Create(Filename,false);
    try
      // сохраняем текущий макет всех форм
      DockMaster.SaveLayoutToConfig(XMLConfig);
      XMLConfig.WriteToDisk;
    finally
      XMLConfig.Free;
    end;
  except
    on E: Exception do begin
      MessageDlg('Ошибка',
        'Ошибка сохранения макета в файл '+Filename+':'#13+E.Message,mtError,
        [mbCancel],0);
    end;
  end;
end;

Загрузка макета

procedure TMainIDE.LoadLayout(Filename: string);
var
  XMLConfig: TXMLConfigStorage;
begin
  try
    // загружаем XML-файл конфигурации
    XMLConfig:=TXMLConfigStorage.Create(Filename,True);
    try
      // восстанавливаем макет
      // это закроет ненужные формы и вызовет OnCreateControl для всех необходимых форм
      DockMaster.LoadLayoutFromConfig(XMLConfig);
    finally
      XMLConfig.Free;
    end;
  except
    on E: Exception do begin
      MessageDlg('Ошибка',
        'Ошибка загрузки макета из файла '+Filename+':'#13+E.Message,mtError,
        [mbCancel],0);
    end;
  end;
end;

Увеличение/Уменьшение размеров

Менеджер стыковки может увеличивать/уменьшать размеры пристыкованных соседей. Это делается через всплывающее меню заголовка узла или в коде с помощью функции DockMaster.ManualEnlarge:

 function ManualEnlarge(Site: TAnchorDockHostSite; Side: TAnchorKind; OnlyCheckIfPossible: boolean): boolean;

Site - дочерний узел, Side - сторона узла, которая растянется. Если вы хотите только проверить, возможно ли увеличение, установите OnlyCheckIfPossible в true.

Растянуть один, ужать другой

Ужать соседний Object Inspector, растянуть Messages: щелкните правой кнопкой мыши заголовок Messages и выберите Enlarge right side(Увеличить правую сторону). Два сплиттера будут изменены в размерах.

Anchordocking before enlarge1.png ⇒ ⇒ ⇒ узел Messages растягивается вправo: ⇒ ⇒ ⇒ Anchordocking after enlarge1.png

Растянуть один, ужать остальные

Сожмите разделитель с одной стороны, растяните оба соседних разделителя, разверните разделитель кзади, растяните Control, уменьшите элементы управления при повороте разделителя. Щелкните правой кнопкой мыши по заголовку Source Editor 1, затем нажмите Enlarge bottom side(Увеличить нижнюю сторону).

Anchordocking before enlarge2.png ⇒ ⇒ ⇒ становится ⇒ ⇒ ⇒ Anchordocking after enlarge2.png

Общие настройки стыковки

Пакет AnchorDocking предоставляет диалог для настройки некоторых свойств DockMaster. Диалог находится в модуле AnchorDockOptionsDlg, и вы можете использовать его весьма просто:

uses ... AnchorDockOptionsDlg;
...
procedure TMainIDE.FormCreate(Sender: TObject);
...
begin
  ...
  DockMaster.OnShowOptions:=@ShowAnchorDockOptions;
  ...
end;

Это добавит новый пункт меню во всплывающие меню заголовков стыковочных узлов и страниц под названием Docking options(Опции стыковки).

Стыковка в IDE

Если вам не нравится внешний вид "обособленных окон" по умолчанию в среде IDE Lazarus и вы предпочитаете единое окно (например, как RAD Studio™), вы можете установить пакет с именем AnchorDockingDsgn. Этот пакет делает окна стыкуемыми (lazarus/components/anchordocking/design/anchordockingdsgn.lpk). Удалите все другие менеджеры стыковки (например, easydockmgrdsgn).

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

Вы можете сохранить макет через пункт меню Tools / Save window layout as default(Инструменты/Сохранить макет окна по умолчанию). Это сохраняет настройки в ~/.lazarus/anchordocklayout.xml и восстанавливает их при запуске IDE.


Прим.перев.: на самом деле, на момент перевода статьи расположение окон в IDE сохраняется в Tools(Сервис) / Desktops(Рабочие столы) / Manage desktops (Управление рабочими столами), а настройки хранятся в environmentoptions.xml в каталоге с прочими настройками Лазаруса.


Вы также можете сохранить макет в файл и загрузить его позже.

Начиная с Lazarus 1.1 вы можете передавать параметр командной строки

./lazarus --anchordocklayout=<filename>

Вот пример того, как выглядит стыкуемая IDE в Windows 7:

Laz IDE v1.2.6 Docked.png


Это пример того, как выглядит стыкуемая IDE ( пакеты AnchorDockingDsgn и sparta_DockedFormEditor) в Windows 10:

Lazarus IDE v1.8.4 docked.png


Внешний вид (как и заголовки) можно изменить, щелкнув по ним правой кнопкой мыши.

docking headers.gif

Зачем использовать Anchors(привязки) вместо Align(выравнивания)?

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


Макеты, которые можно создавать с помощью выравнивания

Выравнивание может создавать только следующие макеты:

Anchordocking align layout1.png

Элементы управления с alTop всегда находятся вверху, заполняя всю горизонтальную ширину. Это потому, что LCL сначала выравнивает все элементы управления с помощью alTop, затем всех alBottom, затем alLeft, затем alRight и, наконец, alClient.

Макеты, которые можно создавать с помощью выравнивания и панелями

Можно смонтировать выравнивание макетов с помощью скрытых панелей. Затем можно создать любой макет, который можно рекурсивно разбить на две части. Тогда вы можете создать, например:

Anchordocking align panels layout1.png

Для этого требуется только одна скрытая панель.

Изменение макетов

Теперь пользователь хочет расширить FPDocEditor по горизонтали (и ужать CodeExplorer). С помощью AnchorDocking вы можете просто щелкнуть правой кнопкой мыши по заголовку FPDocEditor и выбрать Увеличить правую сторону.

Anchordocking align panels layout2.png

Другие стыковочные движки требуют как минимум 2 панели. Один для SrcEditor, Messages, FPDocEdit, CodeExpl и один для SrcEdit и Messages. Большинство стыковочных макетов даже не предоставляют простой способ изменить макет таким способом. Алгоритм, допускающий это изменение макета, должен анализировать всю структуру, как если бы не было панелей, и должен отражать многие вещи. По сути, алгоритм должен делать то же самое, что и алгоритм пристыковки, но с дополнительной работой по переводу макета с использованием выравнивания плюс скрытых панелей.

Макеты, которые невозможны с выравниванием и панелями

Теперь пользователь хочет расширить SourceEditor1 по горизонтали (и ужать ObjectInspector):

Anchordocking impossible with align panels1.png

Такая компоновка невозможна при выравнивании и панелях, поскольку нельзя разрезать его на две половины. То же самое для стыковки с привязкой

Anchordocking impossible with align panels2.png

Заключение

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

Старый/устаревший механизм стыковки

Создание TLazDockingManager

  DockingManager:=TLazDockingManager.Create(Self);

Параметр Self используется только в качестве указания владельца. Это означает, что когда основная форма освобождается, DockingManager также освобождается. Вы можете использовать nil и освободить DockingManager самостоятельно.

Необязательное: загрузка конфигурации

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

  Config:=TXMLConfigStorage.Create('config.xml',true);
  DockingManager.LoadFromConfig(Config);
  Config.Free;

Это загружает файл config.xml. Конфиг может быть создан функцией SaveToConfig. См. ниже.

Преобразование формы/элемента управления в стыкуемый

Создаем TLazControlDocker для каждой формы/элемента управления, которые должны быть стыкуемыми

  ControlDocker1:=TLazControlDocker.Create(Self);
  ControlDocker1.Name:='DockerForm1';
  ControlDocker1.Manager:=DockingManager;

Необязательное: сохранение пользовательской конфигурации на жесткий диск

Когда программа закрывается, вы можете сохранять пользовательскую конфигурацию на диск

  Config:=TXMLConfigStorage.Create('config.xml',true);
  DockingManager.SaveToConfig(Config);
  Config.WriteToDisk;
  Config.Free;

Ссылки