Sign in Join
Wiki copytemporary

LCL Drag Drop/fr: what changed

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

OldNewLine
11Guide de DoDi pour glisser(drag), déplacer(drop), déposer(Dock)
22
33Les contrôles dans un GUI peut être attrapée avec la souris, déplacés vers d'autres endroits, et déposés par dessus d'autres contrôles ou sur le bureau. Lorsque le contrôle glissé est déplacé vers un emplacement différent, l'opération est appelée [[LCL Drag Dock|"glisser déposer"]]. Par ailleurs, le contrôle source et le contrôle cible peuvent échanger des informations ou interagir de toute autre manière, ce qu'on appelle une opération de "glisser-déposer".
44
55Mais tout cela ne fonctionne pas de lui-même, une application doit configurer les opérations permises de sorte que la bibliothèque LCL puisse savoir ce qu'il faut faire avec chaque contrôle simple dans un GUI. Les opérations sophistiquées exigent davantage de code pour la gestion du retour visuel à l'utilisateur de l'application, et ce qui va se passer quand le contrôle glissé sera finalement déposé.
66
77## Glisser Déplacer
88
99C'est seulement une action de glisser simple et originale. Les acteurs sont:
1010
1111- Un contrôle d'origine que l'on peut glisser dans le GUI
1212- Un objet qui glisse, dérivés de TDragObject
1313- des fonctions d'aide
1414- des événements
1515
1616Maintenant, jetons un œil à la manière dont ils travaillent ensemble, basé sur l'implémentation initiale en Delphi pour plus de clarté. L'implémentation de la bibliothèque LCL est quelque peu différente dans l'utilisation des objets d'aide, les détails seront discutés plus loin.
1717
1818### La source de glissement
1919
2020Un contrôle peut être rendu déplaçable en fixant sa propriété **DragMode** à **dmAutomatic**. Lorsque l'utilisateur appuie avec le bouton gauche de la souris sur un tel contrôle, le pointeur de la souris change en un indicateur de glissement jusqu'à ce que l'utilisateur relâche le bouton, ou annule l'opération en appuyant sur la touche Escape. L'indicateur suit désormais les mouvements de la souris et change sa forme, conformément à ce qui se passera lorsque le contrôle sera déplacé sur l'emplacement du moment.
2121
2222Le glissement peut également être lancé dans le code, en appelant la source.BeginDrag. Dans les deux cas, la procédure d'aide DragInitControl est appelé pour démarrer le glissement. Le contrôle initial lève un évènement StartDrag, là où l'application peut fournir un objet de glissement usuel. En cas d'absence d'un tel objet, un objet par défaut est créé. Des structures de données internes pour la rétroaction visuelle et plus sont initialisées. Alors DragTo et appelée pour montrer que le glissement a commencé.
2323
2424### L'objet qui glisse
2525
2626A drag object receives all user input while dragging. In the default implementation it reacts by calling either DragTo or finally DragDone.
2727
2828The drag object also is responsible for the visual feedback:
2929
3030- GetDragCursor returns the mouse pointer shape.
3131- GetDragImages returns a list of drag images, to be attached to the mouse pointer.
3232- ShowDragImage and HideDragImage implement the visual feedback.
3333
3434The Finished method notifies the source control when dragging stops. In case of a cancel'd operation it invokes source.DragCanceled, followed by source.DoEndDrag in either case, which raises an EndDrag event.
3535
3636#### LCL Modifications
3737
3838The current LCL implementation has removed input processing from the drag object, so that the application can no more customize the UI. And the LCL implementation is far from being okay :-(
3939
4040Also the drag object is bypassed in the presentation of the visual feedback.
4141
4242### Helper Functions
4343
4444Helper functions primarily allow for access to protected properties and methods of the controls and other classes, from outside the Controls unit. They also can perform common tasks, and can encapsulate platform specific and other implementation details.
4545
4646#### General Helpers
4747
4848**DragTo** determines the current drag target, sends notifications to the involved controls, and manages the visual feedback. It also handles the delayed start of a dragging operation, i.e. can wait for the mouse moving away far enough from the starting point.
4949
5050**DragDone** terminates dragging, either with a drop or cancel of the operation.
5151
5252**CancelDrag** is protected against false calls, otherwise it defers further actions to DragDone.
5353
5454#### Special Helpers
5555
5656Some more public helper procedures exist, which are undocumented in Delphi and are not required for customized dragging operations.
5757
5858**DragFindWindow** searches for a drag target window (platform specific).
5959
6060**DragInit** initializes the internal management, like mouse capture, and the visual feedback.
6161
6262**DragInitControl** creates the drag object, then calls DragInit.
6363
6464**SetCaptureControl** handles the mouse capture.
6565
6666### Events
6767
6868#### OnStartDrag/Dock
6969
7070This event occurs when the operation starts. The handler can provide a custom DockObject for the operation.
7171
7272#### OnDrag/DockOver
7373
7474This event notifies a possible target, when an object is dragged over it. The handler can signal to accept or reject an drop.
7575
7676The event signals not only mouse moves, but also when the mouse enters or leaves a target control.
7777
7878An OnDockOver event occurs on the DockSite, not on the target control under the mouse. The handler can signal to deny an drop, and can adjust the visual feedback. The event occurs when the mouse enters or leaves a control, and with every single movement of the mouse.
7979
8080#### OnDrag/DockDrop
8181
8282This event notifies the target control of the end of a drag operation.
8383
8484#### OnEndDrag/Dock
8585
8686This event notifies the source control of the end of a drag operation.
8787
8888### Docking specific Events
8989
9090(this section should be moved to docking topic)
9191
9292#### OnGetSiteInfo
9393
9494This event occurs during the search for a qualifying dock site. Multiple dock sites can overlap each other, reside in overlapping windows, or can be invisible. Every candidate must supply an influence rectangle (catching area), and can signal to reject an drop. The drag manager selects the most appropriate dock site as the target for subsequent OnDockOver events.
9595
9696#### OnUnDock
9797
9898This event occurs when the dragged control has to be removed from its host dock site.
9999
100100It's unclear what should happen when the handler denies to undock the control.
101101
102102## LCL Implementation
103103
104104The Delphi implementation of dragging has many flaws, in detail with regards to docking. Until now nobody seems to understand the details of the Delphi dragging model, most code was copied from the VCL and consequently implements exactly the same misbehaviour. This section, and more important the docking specific page, shall shed some light on the dragging model in general and the severe design and implementation flaws in the Delphi implementation.
105105
106106The current LCL implementation uses a DragManager object and drag/dock performers instead of helper functions. The reason for this breaking change is unclear - who can explain?
107107
108108While the Delphi model must be provided for compatibility reasons, the introduction of a DragManager class and object (singleton) allows for the implementation of an alternative drag manager, with improved behaviour, and allows an application to select the most appropriate manager.
109109
110110### DragManager
111111
112112This object handles the captured input, provides helper methods, and stores dragging and docking parameters.
113113
114114It's questionable whether the drag object shall not be allowed to handle user input. It makes the system safer, but disallows applications to extend the user interface for specific dragging operations.
115115
116116The helper methods require different calls, but this is harmless as long as they are only called from LCL components.
117117
118118More critical is the storage of dragging parameters in the DragManager object, which vanish when a different drag manager is installed. This is fatal in case of the list of registered dock sites :-(
119119
120120### Drag Performers
121121
122122The internal use of different classes for dragging and docking is okay in so far, as the procedures differ significantly between drag-drop and drag-dock operations. Nonetheless common actions should use common code, e.g. inherited from the common base class.
123123
124124## Message Sequence Chart or UML Sequence Diagram
125125
126126Provided by Tom Verhoeff
127127
128128Something along the lines (this is for Delphi; view with monospaced font):
129129
130-`                  Main            Drag          (Optional)        Drag`\
131-`  User            Event          Source           Drag           Target`\
132-` (Mouse)          Loop           Control          Object         Control`\
133-`    =               =               =                               =`\
134-`    |               |               |                               |`\
135-`   1|--MouseDown--->|               |                               |`\
136-`    |              2#--OnMouseDown->|                               |`\
137-`    |               |              3#                               |`\
138-`    |              4#<-BeginDrag()--#                               |`\
139-`    |               #               #                               |`\
140-`    |               |               |                               |`\
141-`    |              5#--OnStartDrag->|                               |`\
142-`    |               #              6#----Create---->=               |`\
143-`    |               |               #               |               |`\
144-`   7|--MouseMove--->|               |               |               |`\
145-`    |              8#-----------------------------------OnDragOver->|`\
146-`    |               #               |               |              9#`\
147-`    |               #               |               |               #`\
148-`    |               |               |               |               |`\
149-`  10|---MouseUp---->|               |               |               |`\
150-`    |             11#-----------------------------------OnDragDrop->|`\
151-`    |               #               |               |             12#`\
152-`    |               #               |               |               #`\
153-`    |               #---OnEndDrag-->|               |               |`\
154-`    |               |             13#----Destroy--->=               |`\
155-`    |               |               |                               |`
130+``` pascal
131+ Main Drag (Optional) Drag
132+ User Event Source Drag Target
133+ (Mouse) Loop Control Object Control
134+ = = = =
135+ | | | |
136+ 1|--MouseDown--->| | |
137+ | 2#--OnMouseDown->| |
138+ | | 3# |
139+ | 4#<-BeginDrag()--# |
140+ | # # |
141+ | | | |
142+ | 5#--OnStartDrag->| |
143+ | # 6#----Create---->= |
144+ | | # | |
145+ 7|--MouseMove--->| | | |
146+ | 8#-----------------------------------OnDragOver->|
147+ | # | | 9#
148+ | # | | #
149+ | | | | |
150+ 10|---MouseUp---->| | | |
151+ | 11#-----------------------------------OnDragDrop->|
152+ | # | | 12#
153+ | # | | #
154+ | #---OnEndDrag-->| | |
155+ | | 13#----Destroy--->= |
156+ | | | |
157+```
156158
157159The DragObject is optional. There could be multiple candidate targets. The Main Event Loop determines which event to send to which object, depending on the user action, the cursor location, and the current state of the GUI.
158160
1591614 somehow triggers 5 (there is a delay depending on the Boolean parameter Immediate to BeginDrag).
160162
1611636 determines the location of the MouseDown and may use this to decide on what gets dragged (through GetCursorPos, ScreenToClient, MouseToCell). It can call SetDragImage to visualize a thing being dragged.
162164
163165The chain 7, 8, 9 can occur repeatedly; 9 indicates acceptability of a drop at this target via the Boolean var parameter Accepted.
164166
16516712 is called only if the immediately preceding OnDragOver of this target returned Accepted = True; i.e. Accepted is a precondition of 12.
166168
16716913 receives the parameter Target to know where the drop was accepted; if Target = nil, then the drop was cancelled by the user (MouseUp at an unacceptable location), and OnDragDrop was not performed; if Target \<\> nil, then OnDragDrop was already performed at the Target. The work associated with an actual drop is thus divided over the OnDragDrop (for actions at the target) and OnEndDrag (for actions at the source). Since a Drag Object needs to be destroyed, independent of whether the drop was successful or canceled, it is best to call Free (or Destroy) only in the OnEndDrag handler.
168170
169171Only one drag can be active at any moment; it either ends in a drop or is canceled.
170172
171173There are various other things to be included, but this is the fundamental part. (Maybe also see [Delphi-Central](http://www.delphi-central.com/drag.aspx) or ["Implementing drag-and-drop in controls"](http://www.podgoretsky.com/ftp/Docs/Delphi/D5/dg/controls.html).)
172174
173175I hope this is helpful. Tom
174176
175177---
176178*From the Free Pascal wiki, page "LCL Drag Drop/fr", as it stood on 2009-07-15 after a change by Paulatreides, 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