Articles::Using Drag and Drop in Delphi
Introduction
Due to the graphical nature of Windows the majority of operations
can be performed solely with the mouse. One operation that is often
useful is for the user to be able to drag an object from one
position to another. Fortunately for us, Borland (Inprise) have made
this facility easy to implement for the Delphi developer. The
tutorial will show you how to do this, by explaining and providing
sample code to drag items from one ListBox to another.
The Events Used All
Classes that are descendants of TControl have the following events
available to us: OnDragDrop
OnDragOver OnEndDrag OnStartDrag
I will explain the use of each of these events and all of their
parameters, for more information on this check out the relevant help
files.
OnDragDrop This event is
fired whenever an item is dropped on a control. The majority of the
code needed for implementing drag and drop is entered here. The
parameters are used as follows:
|
Parameter |
Type |
Purpose |
|
Sender |
TObject |
The Sender parameter is the object which received the
dropped item. |
|
Source |
TObject |
This is a pointer to the actual item that is being dragged
(and dropped). In the case of an item in a listbox being
dragged this points to the ListBox and not the actual text
being dragged, so it is up to the developer to handle which
item in the ListBox the intended drag operation is to be
performed on. |
|
X,Y |
Integer |
These are the relative coordinates of where the object was
dropped on the sender object. |
OnDragOver This event is
fired whenever an item is dragged over a control. Its main use is to
decide whether the item can be dropped here and change the cursor to
reflect this. The parameters are used as follows:
|
Parameter |
Type |
Purpose |
|
Sender, Source |
TObject |
Represent the same information as the onDragDrop
event. |
|
X,Y |
Integer |
Represent the same information as the onDragDrop
event. |
|
var Accept |
Boolean |
This should be set to true if the control that the drag is
currently over can accept the dragged item. This is also
reflected by the cursor being either the drag or the no-entry
cursor (These can easily be changed to your own
choice) |
|
State |
TDragState |
This parameter tells you whether the drag operation is just
entering, moving into or leaving the Sender
object. |
OnEndDrag This event is
fired whenever an item is dropped. Unlike th onDrop event the use of
this event is to perform the neccessary operation on the object that
was dragged. This is normally used for cleaning up any thing that
was created in the onStartDrag event. The parameters are used as
follows:
|
Parameter |
Type |
Purpose |
|
Sender |
TObject |
This is the Object that was actually dragged. |
|
Target |
TObject |
This is the Object that the drag object was dropped on. If
the drag operation failed then this is set to nil. |
|
X,Y |
Integer |
The relative coordinates of where the drag object was
dropped on the target parameter. |
OnStartDrag This event is
fired whenever an item first dragged. Its is mainly used to
initialize any variable that are needed for the drag operation. It
is not always needed and will not be used in our simple example.
|
Parameter |
Type |
Purpose |
|
Sender |
TObject |
This is the Object that is beginning to be
dragged. |
|
DragObject |
TDragObject |
This Object allows us to store and pass on a lot more
information about what is being dragged. Check out the help
file for further information on this, when used correctly this
can add great power at low cost to your
applications. | An Example What We Will Do In this example
we will have two listboxes on a form and implement the facility to
allow our users to drag items from one listbox to the other, and
also reposition items in each listbox by dragging and dropping the
selected strings.
Designing
The Interface As this is a very simple application
demonstrating how to implement drag and drop we only need a very
simple application. The code that follows assumes that you have used
the default names that Delphi provides, if not adjust accordingly.
The steps involved are:
- Start a new application.
- On the main form place two TlistBox objects (from the standard
page of the component palette)
- For each ListBox item set the DragMode property to
dmAutomatic (using the Object Inspector)- this means that
we do not need to begin the drag operation manually
- Next use the Object Inspector to generate the events for the
onDragOver and onDragDrop for one of the listboxes,
and set the corresponding events of the other listbox to match
those already generated (by using the drop down list in the Object
Inspector)
That is the interface complete, all we need to
do now is write the actual code.
The Code As seen in the interface section we
have only created to procedure stubs. These are in fact all that we
need to implement our drag and drop.
The DragOver procedure
is implemented as follows:
procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if Source is TListBox then Accept := True;
end;
What we are doing here is making sure that the Object being
dragged onto the listbox is also another listbox (though we only use
the selected item in the listbox) and setting the accept var
accordingly.
Next we need to accept the dropped object and
update the listboxes contents accordingly. This is done in the
DragDrop procedure as follows:
procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
iTemp : integer;
ptTemp : TPoint;
szTemp : String;
begin
{ change the x,y coordinates into a TPoint record }
ptTemp.x:=x;
ptTemp.y:=y;
{ Use a while loop instead of a for loop due to items possible being removed from
listboxes this prevents an out of bounds exception }
iTemp := 0;
While iTemp <= TListBox(Source).Items.Count-1 do
begin
{ look for the selected items as these are the ones we wish to move }
if TListBox(Source).selected[iTemp] then
begin
{ use a with as to make code easier to read }
With Sender as TListBox do
begin
{ need to use a temporary variable as when the item is deleted the indexing
will change }
szTemp := TListBox(Source).items[iTemp];
{ delete the item that is being dragged }
TListBox(Source).items.Delete(iTemp);
{ insert the item into the correct position in the listbox that it was dropped on }
items.Insert(itemAtPos(ptTemp,true),
szTemp);
end;
end;
inc(iTemp);
end;
end;
I have thoroughly commented this procedure, so will not
explain its workings here. All that it is doing is deleting the
dragged item and adding it in the correct place in the listbox that
it was dropped onto.
Closing
Comments I hope this tutorial has provided enough
information for you to use drag and drop in your applications. The
example shown is a very simple one but provides the basic framework
for more complex tasks. In a later article or tutorial I intend to
dig deeper into the use of TDragObject.
|