Sign in Join
Wiki copytemporary

LCL Drag Dock/ru: what changed

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

Title: LCL Drag Dock/ru

OldNewLine
1+Элементы управления или целые формы в графическом интерфейсе пользователя можно склеить и снова отсоединить, перетаскивая их мышью. Такая стыковка похожа на [[LCL Drag Drop|drag-drop]], но отличается в некоторых аспектах.
2+
3+## Операции
4+
5+Операция стыковки организована так же, как и любая другая операция перетаскивания.
6+
7+### DragInit
8+
9+Как обычно, при запуске стыковки необходимо активировать визуальную обратную связь.
10+
11+### DragTo
12+
13+На ходу нужно сделать пару шагов:
14+
15+- Хочет ли пользователь пристыковаться вообще
16+- Определение возможных целевых стыковочных узлов
17+- Определение точной зоны бросания элемента управления
18+- Визуальная обратная связь
19+
20+### DragDone
21+
22+При бросании элемента управления стыковка может быть заблокирована по нескольким причинам. Трудно объяснить, почему стыковочный узел должен отказывать в откреплении перетаскиваемого элемента управления, когда он, наконец, стаскивается. Возможны следующие случаи:
23+
24+- Элемент управления пристыкован к новому сайту док-станции.
25+- Перетаскиваемый элемент управления становится плавающим
26+ - как есть, если он уже был плавающим, или когда он может стать самостоятельно плавающим это TWinControl),
27+ - или завернутый в новую плавающую форму.
28+- Вся операция прервана.
29+
30+## Обзор стыковочных элементов
31+
32+Помимо drag-drop участников, на сцену выходят еще несколько участников:
33+
34+- Стыковочные узлы (Dock sites)
35+- Стыковочные прямоугольники в качестве визуальной обратной связи
36+- Диспетчеры стыковки (Dock managers)
37+
38+Введение диспетчеров стыковки создало кучу новых проблем с плохой интеграцией в модель неуправляемой док-станции. Давайте пока проигнорируем [[LCL Managed Docking|"управляемую" стыковку]] и рассмотрим только "неуправляемую" стыковку.
39+
40+### Прикрепляемый элемент (Dock Source)
41+
42+Элемент управления или форму можно сделать прикрепляемыми, установив для его свойства `DragKind` значение `dkDock`.
43+
44+### Стыковочные узлы (Dock Sites)
45+
46+Для стыковки требуются специальные целевые зоны сброса \[для прикрепляемого элемента\], называемые стыковочными узлами. TWinControl становится такой стыковочной целью, при установке его свойства `DockSite` в значение `True`.
47+
48+Прикрепленные элементы управления находятся в отдельном массиве элементов, отделенном от других компонентов в элементе управления контейнера. Для правильного поведения настоятельно рекомендуется изначально не иметь никаких других элементов управления на стыковочном сайте и заполнять его только закрепленными элементами управления.
49+
50+#### Плавающие стыковочные узлы
51+
52+Другой вид стыковочных узлов используется для незакрепленных (плавающих) элементов управления. Когда элемент управления бросается за пределы стыковочного узла, и это не TWinControl, для него создается новая форма в месте размещения. Когда плавающий элемент управления позже стыкуется со стыковочным узлом, плавающая форма уничтожается.
53+
54+Приложение может создавать другие формы для плавающих элементов управления, например, несколько элементов управления могут быть закреплены внутри и вне такой формы.
55+
56+### Стыковочный прямоугольник (DockRect)
57+
58+Как и в операциях drag-drop, при операции стыковки за указателем мыши следует значок в форме прямоугольника. Но значок стыковочного прямоугольника может динамически изменять свой размер и положение, чтобы сигнализировать о положении и размере элемента управления, когда последний бросается в текущем месте.
59+
60+Когда не удается найти принимающий стыковочный узел или когда пользователь запрещает перетаскивание, удерживая клавишу Ctrl, DockRect отражает плавающий размер и положение перетаскиваемого элемента управления. Плавающий размер инициализируется исходным размером перетаскиваемого элемента управления и обновляется при перемещении элемента управления. В противном случае стыковочный узел может определить размещение и размер брошенного элемента управления.
61+
62+Реализация Delphi запоминает координаты нарисованного DockRect в `EraseDockRect`, так что старый фрейм может быть удален с экрана с помощью XOR-рисования, когда это необходимо.
63+
64+### Стыковочный объект (DockObject)
65+
66+В операции стыковки используется специальный DockObject, производный от TDragObject. Непонятно, почему этот класс вводит новые методы вместо того, чтобы переопределять существующие виртуальные методы для различной визуальной обратной связи.
67+
68+Унаследованный DragTarget - это целевой стыковочный сайт в стыковке. Добавленные свойства `DropOnControl` и `DropAlign` указывают, где и как перетаскиваемый элемент управления должен располагаться относительно уже закрепленного элемента управления.
69+
70+### Помощники (Helpers)
71+
72+В классы TControl и TWinControl добавлен ряд вспомогательных методов и полей для внутреннего управления закрепленными элементами управления и настройки процесса стыковки. Большинство этих помощников играют особую роль в процессе стыковки и будут описаны в рабочем процессе ниже.
73+
74+(место для описания общих элементов)
75+
76+## Механика процесса
77+
78+Это подробное описание необходимых действий до, во время и после закрепления элемента управления.
79+
80+### Предпосылки
81+
82+Элемент управления становится стыкуемым, если для его `DragKind` задано значение `dkDock`. Для стыковочного узла больше ничего не требуется.
83+
84+Глобальный список содержит все стыковочные узлы в приложении. Стыковочные узлы добавляются и удаляются из этого списка при изменении их свойства `DockSite`.
85+
86+#### RegisterDockSite
87+
88+Стыковочные узлы могут быть частично или полностью покрыты другими формами, но в любом случае должны действовать как стыковочные цели. Эта процедура регистрирует и отменяет регистрацию элементов управления в приложении в качестве стыковочных узлов, так что даже скрытые кандидаты могут быть найдены при перетаскивании источника стыковчного узла по экрану.
89+
90+#### GetSiteInfo
91+
92+Метод `TWinControl.GetSiteInfo` возвращает прямоугольник влияния (захвата), связанный со стыковочным узлом. Это соглашение позволяет, например, скрыть стыковочные узлы в графическом интерфейсе, без превращения их в недоступные для удаления. Реализация по умолчанию возвращает видимый размер элемента управления, увеличенный на определенную величину в любом направлении.
93+
94+### DragInit
95+
96+Стыковка запускается автоматически, когда для элемента управления задано значение `DragKind=dkDock` и `DragMode=dmAutomatic`, а на этом элементе управления нажата левая кнопка мыши. TControl предоставляет метод `BeginAutoDrag` для этого случая и метод `BeginDrag` для запуска программной стыковки, когда `DragMode=dmManual`.
97+
98+`DockObject` создается либо обработчиком `OnDockStart` исходного элемента управления (`TControl.DoStartDock`), либо диспетчером перетаскивания, если такой объект не был предоставлен. `DockRect` инициализируется прямоугольником элемента управления. Для удобного положения `DockRect` во время перемещений запоминается смещение указателя мыши на `DockRect`.
99+
100+Захват ввода перемещается в элемент управления или в его родительский элемент `TWinControl`, когда элемент управления не может получать системные (Windows) сообщения.
101+
102+Когда перетаскивание должно начаться немедленно, вызывается `DragTo`.
103+
104+### DragTo
105+
106+`DragTo` проверяет наличие отложенного запуска и ничего не делает, если порог перемещения мыши еще не достигнут.
107+
108+В противном случае ищется цель перетаскивания. Когда цель изменяется, `DoDragOver` отправляет в цель `dmDragLeave` и `dmDragEnter` в виде сообщений `CM_DRAG`.
109+
110+Сообщение `dmDragMove` отправляется таким же образом и обрабатывается в `TWinControl.DockOver`, который позиционирует `DockRect` и вызывает обработчик `OnDockOver`. Результат указывает, будет ли принято решение о сбросе, и соответственно обновляется визуальная обратная связь.
111+
112+#### Горести Delphi
113+
114+Следующий шаг в реализации Delphi - фиктивный. Когда cброс(dropping) отклонен, `DockRect` сбрасывается в плавающее положение и размер перетаскиваемого элемента управления, что уже должно было быть сделано раньше. Кроме того, на стыковочном узле выполняется поиск `DropOnControl` и определяется `DropAlign`. Ни одно из этих значений не отражается в ранее определенном `DockRect`, поэтому предполагаемый эффект становится видимым в лучшем случае (если вообще когда-либо) после следующего движения мыши. Когда `DropOnControl` не найден, что весьма вероятно на неуправляемом стыковочном узле, `DockRect` будет охватывать весь стыковочный узел - что не очень важно. Когда `DropOnControl` найден, значение `DropAlign` не определено; реализация Delphi использует это значение для настройки `DockRect` на верхнюю (левую ...) половину `DropOnControl`, но такое размещение отброшенного элемента управления может иметь смысл только тогда, когда сам `DropOnControl` соответствующим образом сокращается. В управляемом стыковочном узле DockManager может настраивать `DockRect`, а затем может уместить затронутые элементы управления в указанные границы, но у него нет возможности самому определить `DropOnControl` или `DropAlign`. Таким образом, значение `DropOnControl` и `DropAlign` вызывает сомнения как для управляемых, так и для неуправляемых стыковочных узлов.
115+
116+При лучшем решении этот шаг будет полностью опущен, а обработчики событий и стыковочного узла будут управлять визуальной обратной связью и окончательным сбросом или оставят все это установленному DockManager.
117+
118+### DragDone
119+
120+Когда перетаскивание завершено, либо при отмене, либо при успешном перетаскивании, захват снимается, а визуальная обратная связь удаляется с экрана. Дальнейшая процедура зависит от успеха операции.
121+
122+#### Ручная стыковка
123+
124+Метод `TControl.ManualDock` обходит все действия пользователя и закрепляет элемент управления на стыковочном узле или делает его плавающим (`TControl.ManualFloat`). Если требуется для дальнейшей обработки запроса, должен быть создан и инициализирован `DockObject` из параметров.
125+
126+#### Сброс внутри стыковочного узла
127+
128+На первом этапе элемент управления логически перемещается на новый стыковочный узел, если только он не будет повторно пристыкован на том же стыковочном узле. Он удаляется из списка элементов управления старого узла и перемещается в список закрепленных элементов управления нового стыковочного узла, а его родительский элемент корректируется соответствующим образом.
129+
130+Наконец, в соответствии с последним `DockRect`, элемент управления помещается в новый родительский элемент. В управляемой стыковочном узле DockManager может при необходимости переставлять закрепленные элементы управления.
131+
132+#### Сброс в никуда
133+
134+Перетаскиваемый элемент управления становится плавающим. Форма может перемещаться сама по себе, но для удобства все элементы управления могут быть заключены в специальный контейнер плавающей формы (по умолчанию: `FloatingDockSiteClass=CustomDockForm`).
135+
136+Сообщение `CM_FLOAT` отправляется в исходный код элемента управления. Когда элемент управления уже плавает, он перемещает свой родительский элемент, и все готово.
137+
138+В противном случае элемент управления устанавливает `DragTarget` на вновь созданный стыковочный узел, а затем закрепляется на этом узле, как и на любом другом целевом узле.
139+
140+#### Отмена сброса
141+
142+Исходный элемент управления получает уведомление `DragCanceled`, вот и все.
143+
144+## События
145+
146+Во время стыковки происходят следующие события:
147+
148+### DragInit
149+
150+Обработчик `StartDrag`/`Dock` может возвращать пользовательский `Drag`/`DockObject`.
151+
152+### DragTo
153+
154+При стыковке зарегистрированные стыковочные узлы получают событие `GetSiteInfo`. Обработчики могут предоставить прямоугольник влияния и указать, допустим ли сброс.
155+
156+Когда цель изменяется, старая и новая цели получают событие `Drag`/`DockOver` с состоянием `dmDragEnter`/`Leave`.
157+
158+Во всех случаях происходит событие `Drag`/`DockOver` в состоянии `dmDragMove`. Обработчик может отклонить перетаскивание и может настроить визуальную обратную связь в данном объекте drag/dock.
159+
160+### DragDone
161+
162+Конечное значение `Drag`/`DockMove` состояния `dmDragLeave` отправляется цели. Это первое событие в программном сбросе элемента управления (`TControl.ManualDock`). Состояние лучше должно быть `dmDragMove`, но реализация Delphi использует `dmDragLeave`.
163+
164+При стыковке событие `UnDock` позволяет исходному сайту отклонить (отменить) сброс. Обработчику событий, стыковочному узлу и стыковочному диспетчеру предлагается последовательно отклонить или выполнить соответствующее внутреннее действие.
165+
166+Если перетаскивание не отклоняется, возникает событие `Drag`/`DockDrop`.
167+
168+Во всех случаях источник получает событие <code>EndDrag<code>/`Dock`.
169+
170+---
171+*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