Sign in Join
Wiki copytemporary

LCL Drag Dock/ru: what changed

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

OldNewLine
11Элементы управления или целые формы в графическом интерфейсе пользователя можно склеить и снова отсоединить, перетаскивая их мышью. Такая стыковка похожа на [[LCL Drag Drop|drag-drop]], но отличается в некоторых аспектах.
22
33## Операции
44
55Операция стыковки организована так же, как и любая другая операция перетаскивания.
66
77### DragInit
88
99Как обычно, при запуске стыковки необходимо активировать визуальную обратную связь.
1010
1111### DragTo
1212
1313На ходу нужно сделать пару шагов:
1414
1515- Хочет ли пользователь пристыковаться вообще
1616- Определение возможных целевых стыковочных узлов
1717- Определение точной зоны бросания элемента управления
1818- Визуальная обратная связь
1919
2020### DragDone
2121
2222При бросании элемента управления стыковка может быть заблокирована по нескольким причинам. Трудно объяснить, почему стыковочный узел должен отказывать в откреплении перетаскиваемого элемента управления, когда он, наконец, стаскивается. Возможны следующие случаи:
2323
2424- Элемент управления пристыкован к новому сайту док-станции.
2525- Перетаскиваемый элемент управления становится плавающим
2626 - как есть, если он уже был плавающим, или когда он может стать самостоятельно плавающим это TWinControl),
2727 - или завернутый в новую плавающую форму.
2828- Вся операция прервана.
2929
3030## Обзор стыковочных элементов
3131
3232Помимо drag-drop участников, на сцену выходят еще несколько участников:
3333
3434- Стыковочные узлы (Dock sites)
3535- Стыковочные прямоугольники в качестве визуальной обратной связи
3636- Диспетчеры стыковки (Dock managers)
3737
3838Введение диспетчеров стыковки создало кучу новых проблем с плохой интеграцией в модель неуправляемой док-станции. Давайте пока проигнорируем [[LCL Managed Docking|"управляемую" стыковку]] и рассмотрим только "неуправляемую" стыковку.
3939
4040### Прикрепляемый элемент (Dock Source)
4141
4242Элемент управления или форму можно сделать прикрепляемыми, установив для его свойства `DragKind` значение `dkDock`.
4343
4444### Стыковочные узлы (Dock Sites)
4545
4646Для стыковки требуются специальные целевые зоны сброса \[для прикрепляемого элемента\], называемые стыковочными узлами. TWinControl становится такой стыковочной целью, при установке его свойства `DockSite` в значение `True`.
4747
4848Прикрепленные элементы управления находятся в отдельном массиве элементов, отделенном от других компонентов в элементе управления контейнера. Для правильного поведения настоятельно рекомендуется изначально не иметь никаких других элементов управления на стыковочном сайте и заполнять его только закрепленными элементами управления.
4949
5050#### Плавающие стыковочные узлы
5151
5252Другой вид стыковочных узлов используется для незакрепленных (плавающих) элементов управления. Когда элемент управления бросается за пределы стыковочного узла, и это не TWinControl, для него создается новая форма в месте размещения. Когда плавающий элемент управления позже стыкуется со стыковочным узлом, плавающая форма уничтожается.
5353
5454Приложение может создавать другие формы для плавающих элементов управления, например, несколько элементов управления могут быть закреплены внутри и вне такой формы.
5555
5656### Стыковочный прямоугольник (DockRect)
5757
5858Как и в операциях drag-drop, при операции стыковки за указателем мыши следует значок в форме прямоугольника. Но значок стыковочного прямоугольника может динамически изменять свой размер и положение, чтобы сигнализировать о положении и размере элемента управления, когда последний бросается в текущем месте.
5959
6060Когда не удается найти принимающий стыковочный узел или когда пользователь запрещает перетаскивание, удерживая клавишу Ctrl, DockRect отражает плавающий размер и положение перетаскиваемого элемента управления. Плавающий размер инициализируется исходным размером перетаскиваемого элемента управления и обновляется при перемещении элемента управления. В противном случае стыковочный узел может определить размещение и размер брошенного элемента управления.
6161
6262Реализация Delphi запоминает координаты нарисованного DockRect в `EraseDockRect`, так что старый фрейм может быть удален с экрана с помощью XOR-рисования, когда это необходимо.
6363
6464### Стыковочный объект (DockObject)
6565
6666В операции стыковки используется специальный DockObject, производный от TDragObject. Непонятно, почему этот класс вводит новые методы вместо того, чтобы переопределять существующие виртуальные методы для различной визуальной обратной связи.
6767
6868Унаследованный DragTarget - это целевой стыковочный сайт в стыковке. Добавленные свойства `DropOnControl` и `DropAlign` указывают, где и как перетаскиваемый элемент управления должен располагаться относительно уже закрепленного элемента управления.
6969
7070### Помощники (Helpers)
7171
7272В классы TControl и TWinControl добавлен ряд вспомогательных методов и полей для внутреннего управления закрепленными элементами управления и настройки процесса стыковки. Большинство этих помощников играют особую роль в процессе стыковки и будут описаны в рабочем процессе ниже.
7373
7474(место для описания общих элементов)
7575
7676## Механика процесса
7777
7878Это подробное описание необходимых действий до, во время и после закрепления элемента управления.
7979
8080### Предпосылки
8181
8282Элемент управления становится стыкуемым, если для его `DragKind` задано значение `dkDock`. Для стыковочного узла больше ничего не требуется.
8383
8484Глобальный список содержит все стыковочные узлы в приложении. Стыковочные узлы добавляются и удаляются из этого списка при изменении их свойства `DockSite`.
8585
8686#### RegisterDockSite
8787
8888Стыковочные узлы могут быть частично или полностью покрыты другими формами, но в любом случае должны действовать как стыковочные цели. Эта процедура регистрирует и отменяет регистрацию элементов управления в приложении в качестве стыковочных узлов, так что даже скрытые кандидаты могут быть найдены при перетаскивании источника стыковчного узла по экрану.
8989
9090#### GetSiteInfo
9191
9292Метод `TWinControl.GetSiteInfo` возвращает прямоугольник влияния (захвата), связанный со стыковочным узлом. Это соглашение позволяет, например, скрыть стыковочные узлы в графическом интерфейсе, без превращения их в недоступные для удаления. Реализация по умолчанию возвращает видимый размер элемента управления, увеличенный на определенную величину в любом направлении.
9393
9494### DragInit
9595
9696Стыковка запускается автоматически, когда для элемента управления задано значение `DragKind=dkDock` и `DragMode=dmAutomatic`, а на этом элементе управления нажата левая кнопка мыши. TControl предоставляет метод `BeginAutoDrag` для этого случая и метод `BeginDrag` для запуска программной стыковки, когда `DragMode=dmManual`.
9797
9898`DockObject` создается либо обработчиком `OnDockStart` исходного элемента управления (`TControl.DoStartDock`), либо диспетчером перетаскивания, если такой объект не был предоставлен. `DockRect` инициализируется прямоугольником элемента управления. Для удобного положения `DockRect` во время перемещений запоминается смещение указателя мыши на `DockRect`.
9999
100100Захват ввода перемещается в элемент управления или в его родительский элемент `TWinControl`, когда элемент управления не может получать системные (Windows) сообщения.
101101
102102Когда перетаскивание должно начаться немедленно, вызывается `DragTo`.
103103
104104### DragTo
105105
106106`DragTo` проверяет наличие отложенного запуска и ничего не делает, если порог перемещения мыши еще не достигнут.
107107
108108В противном случае ищется цель перетаскивания. Когда цель изменяется, `DoDragOver` отправляет в цель `dmDragLeave` и `dmDragEnter` в виде сообщений `CM_DRAG`.
109109
110110Сообщение `dmDragMove` отправляется таким же образом и обрабатывается в `TWinControl.DockOver`, который позиционирует `DockRect` и вызывает обработчик `OnDockOver`. Результат указывает, будет ли принято решение о сбросе, и соответственно обновляется визуальная обратная связь.
111111
112112#### Горести Delphi
113113
114114Следующий шаг в реализации Delphi - фиктивный. Когда cброс(dropping) отклонен, `DockRect` сбрасывается в плавающее положение и размер перетаскиваемого элемента управления, что уже должно было быть сделано раньше. Кроме того, на стыковочном узле выполняется поиск `DropOnControl` и определяется `DropAlign`. Ни одно из этих значений не отражается в ранее определенном `DockRect`, поэтому предполагаемый эффект становится видимым в лучшем случае (если вообще когда-либо) после следующего движения мыши. Когда `DropOnControl` не найден, что весьма вероятно на неуправляемом стыковочном узле, `DockRect` будет охватывать весь стыковочный узел - что не очень важно. Когда `DropOnControl` найден, значение `DropAlign` не определено; реализация Delphi использует это значение для настройки `DockRect` на верхнюю (левую ...) половину `DropOnControl`, но такое размещение отброшенного элемента управления может иметь смысл только тогда, когда сам `DropOnControl` соответствующим образом сокращается. В управляемом стыковочном узле DockManager может настраивать `DockRect`, а затем может уместить затронутые элементы управления в указанные границы, но у него нет возможности самому определить `DropOnControl` или `DropAlign`. Таким образом, значение `DropOnControl` и `DropAlign` вызывает сомнения как для управляемых, так и для неуправляемых стыковочных узлов.
115115
116116При лучшем решении этот шаг будет полностью опущен, а обработчики событий и стыковочного узла будут управлять визуальной обратной связью и окончательным сбросом или оставят все это установленному DockManager.
117117
118118### DragDone
119119
120120Когда перетаскивание завершено, либо при отмене, либо при успешном перетаскивании, захват снимается, а визуальная обратная связь удаляется с экрана. Дальнейшая процедура зависит от успеха операции.
121121
122122#### Ручная стыковка
123123
124124Метод `TControl.ManualDock` обходит все действия пользователя и закрепляет элемент управления на стыковочном узле или делает его плавающим (`TControl.ManualFloat`). Если требуется для дальнейшей обработки запроса, должен быть создан и инициализирован `DockObject` из параметров.
125125
126126#### Сброс внутри стыковочного узла
127127
128128На первом этапе элемент управления логически перемещается на новый стыковочный узел, если только он не будет повторно пристыкован на том же стыковочном узле. Он удаляется из списка элементов управления старого узла и перемещается в список закрепленных элементов управления нового стыковочного узла, а его родительский элемент корректируется соответствующим образом.
129129
130130Наконец, в соответствии с последним `DockRect`, элемент управления помещается в новый родительский элемент. В управляемой стыковочном узле DockManager может при необходимости переставлять закрепленные элементы управления.
131131
132132#### Сброс в никуда
133133
134134Перетаскиваемый элемент управления становится плавающим. Форма может перемещаться сама по себе, но для удобства все элементы управления могут быть заключены в специальный контейнер плавающей формы (по умолчанию: `FloatingDockSiteClass=CustomDockForm`).
135135
136136Сообщение `CM_FLOAT` отправляется в исходный код элемента управления. Когда элемент управления уже плавает, он перемещает свой родительский элемент, и все готово.
137137
138138В противном случае элемент управления устанавливает `DragTarget` на вновь созданный стыковочный узел, а затем закрепляется на этом узле, как и на любом другом целевом узле.
139139
140140#### Отмена сброса
141141
142142Исходный элемент управления получает уведомление `DragCanceled`, вот и все.
143143
144144## События
145145
146146Во время стыковки происходят следующие события:
147147
148148### DragInit
149149
150150Обработчик `StartDrag`/`Dock` может возвращать пользовательский `Drag`/`DockObject`.
151151
152152### DragTo
153153
154154При стыковке зарегистрированные стыковочные узлы получают событие `GetSiteInfo`. Обработчики могут предоставить прямоугольник влияния и указать, допустим ли сброс.
155155
156156Когда цель изменяется, старая и новая цели получают событие `Drag`/`DockOver` с состоянием `dmDragEnter`/`Leave`.
157157
158158Во всех случаях происходит событие `Drag`/`DockOver` в состоянии `dmDragMove`. Обработчик может отклонить перетаскивание и может настроить визуальную обратную связь в данном объекте drag/dock.
159159
160160### DragDone
161161
162162Конечное значение `Drag`/`DockMove` состояния `dmDragLeave` отправляется цели. Это первое событие в программном сбросе элемента управления (`TControl.ManualDock`). Состояние лучше должно быть `dmDragMove`, но реализация Delphi использует `dmDragLeave`.
163163
164164При стыковке событие `UnDock` позволяет исходному сайту отклонить (отменить) сброс. Обработчику событий, стыковочному узлу и стыковочному диспетчеру предлагается последовательно отклонить или выполнить соответствующее внутреннее действие.
165165
166166Если перетаскивание не отклоняется, возникает событие `Drag`/`DockDrop`.
167167
168-Во всех случаях источник получает событие <code>EndDrag<code>/`Dock`.
168+Во всех случаях источник получает событие EndDrag/`Dock`.
169169
170170---
171171*From the Free Pascal wiki, page "LCL Drag Dock/ru", as it stood on 2021-01-18 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history