Drag & Drop in ListBox

Top  Previous  Next

The TListBox Delphi component displays a collection of items in a scrollable list. Delphi makes it easy to program dragging and dropping into your applications.

 

Here's how to allow a user to rearrange (change item's position) the items of a ListBox using drag and drop:

 

  Drop a TListBox (named ListBox1) on a form

  Add several strings using the Items property

  Set ListBox1's DragMode to dmAutomatic (in Form's OnCreate or using Object Inspector at design-time).

 

  Handle ListBox-es MouseDown, DragOver and DragDrop events

 

var // form level

  StartingPoint : TPoint;

 

implementation

 

...

 

procedure TForm1.FormCreate(Sender: TObject) ;

begin

  ListBox1.DragMode := dmAutomatic;

end;

 

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer) ;

var

  DropPosition, StartPosition: Integer;

  DropPoint: TPoint;

begin

  DropPoint.X := X;

  DropPoint.Y := Y;

  with Source as TListBox do

  begin

    StartPosition := ItemAtPos(StartingPoint,True) ;

    DropPosition := ItemAtPos(DropPoint,True) ;

 

    Items.Move(StartPosition, DropPosition) ;

  end;

end;

 

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean) ;

begin

  Accept := Source = ListBox1;

end;

 

procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer) ;

begin

  StartingPoint.X := X;

  StartingPoint.Y := Y;

end;

 

 

Drag and Drop between Components

 

How do I implement drag and drop between two list boxes on a form?

 

Dragging items from one list box and dropping them into another is, with Delphi, amazingly easy to implement. I'm going to show you a couple of very simple routines to handle two types of dragging and dropping. The first involves moving items from one list into another, and the second involves dragging items within the same list box.

 

Dragging Between Two List Boxes

 

To perform dragging between two list boxes, you first have to make the items in the source list box "drag-able." The easiest way to do this is to set the DragMode property of the list box to dmAutomatic. (I realize there are those of you who prefer to have more precise control over dragging operations by programmatically starting and ending drag operations with BeginDrag and EndDrag. But since this discussion is mainly geared towards the novice, I'm going to skip that topic in favor of getting the user up and running right away).

 

The second thing to do is to set the MultiSelect property to True. This is purely optional, but it's quite useful for transferring multiple items between lists.

 

The next thing you have to do is let the target list accept items being dropped. The way you typically do this is with the target list's OnDragOver event. Here's a simple example:

 

procedure TMainForm.lstStudyTracersDragOver(Sender, Source: TObject; X,

Y: Integer; State: TDragState; var Accept: Boolean);

begin

{Only let another TListBox drop items}

if Source is TListBox then

  Accept := True

else

      Accept := False;

end;

 

The conditional above checks to see if the source is a list box. If it is, the target sets its Accept property to true. The method that controls dragging and dropping is the target list box's OnDragDrop method. But instead of writing code in the method to handle the dropped items directly, I use a generalize method instead:

 

procedure TransferItemsNoDups(Sender, Source : TObject);

var

I, N : Integer;

Found : Boolean;

begin

with (Source AS TListBox) do begin

  for I := 0 to Items.Count - 1 do

    if Selected[I] then begin

      Found := False;

      for N := 0 to (Sender AS TListBox).Items.Count - 1 do

        if (Sender AS TListBox).Items[N] = Items[I] then

          Found := True;

 

      if NOT Found then

        (Sender AS TListBox).Items.Add(Items[I]);

    end;

end;

end;

 

Notice the name of the procedure: TransferItemsNoDups. This method will iterate through the items in the source list. For each selected item to be transferred, it checks to see if the item exists in the target list. If it does, then the item is skipped; otherwise, it's added to the end of the list. Since this came out of an application I wrote, there's one bit of code I didn't insert that you might consider doing yourself; that is, some code that will delete the selected items once they're transferred. In that case, you'd probably write a procedure that looks like the following:

 

procedure TransferItems(Sender, Source : TObject);

var

I : Integer;

Found : Boolean;

begin

with (Source AS TListBox) do begin

  for I := 0 to Items.Count - 1 do

    if Selected[I] then

      (Sender AS TListBox).Items.Add(Items[I]);

 

      for I := 0 to Items.Count - 1 DownTo 0 do

        if Selected[I] then

              Items.Delete(I);

end;

end;

 

Notice that I didn't do any duplicate checking in the procedure above. That's because it would be useless. This methodology is best used between two lists where you allow your user to drag and drop between the two.

 

Moving Items Within a List Box

 

Moving items within a list box is a pretty simple thing to do. Look at the procedure below:

 

procedure MoveItems(var Target : TObject; X, Y : Integer);

var

NPos : Integer;

begin

with Target AS TListBox do begin

  NPos := ItemAtPos(Point(X, Y), False);

  if (NPos >= Items.Count) then

    Dec(NPos);

  {Move selected item to the new position}

  Items.Move(ItemIndex, NPos);

  ItemIndex := NPos;

end;

end;

 

The first thing that happens in the code is the drop position is read into an integer variable. Then the procedure checks the value of the position to determine if it's in the range of the items of the list box. If not, its value is decremented to either 0 or to the count of the items. After that, the Move method is invoked to move the currently selected item to the new drop position, and the currently selected item is reselected in the position it was dropped.

 

I didn't cover all the subtle nuances of drag and drop here. My purpose was to give you something to start with. I suggest you pore over the Delphi user manual and online help for more in-depth discussions of drag and drop functionality.

 

Copyright © 1997 Brendan V. Delumpa All Rights Reserved