I need to Drag and Drop multiple items inside my Tlistbox
.
The code which I am referring to is
var
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;
from here.
It works fine but what I need to achieve is like this
.
Why I want this is because there is certain order that corresponds to these listbox items. So instead of just having manually select each item and drag drop it,I want to enable multiple drag drop.
Any views on how can I achieve this is appreciated.
Also can suggest the use of other components if the following is possible using the same.
This is surprisingly tricky to do well (see my first revision of this answer for an example of how to get it wrong).
Here's a rather easy to understand approach that solves the problem by:
procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
ListBox: TListBox;
i, TargetIndex: Integer;
SelectedItems: TStringList;
begin
Assert(Source=Sender);
ListBox := Sender as TListBox;
TargetIndex := ListBox.ItemAtPos(Point(X, Y), False);
if TargetIndex<>-1 then
begin
SelectedItems := TStringList.Create;
try
ListBox.Items.BeginUpdate;
try
for i := ListBox.Items.Count-1 downto 0 do
begin
if ListBox.Selected[i] then
begin
SelectedItems.AddObject(ListBox.Items[i], ListBox.Items.Objects[i]);
ListBox.Items.Delete(i);
if i<TargetIndex then
dec(TargetIndex);
end;
end;
for i := SelectedItems.Count-1 downto 0 do
begin
ListBox.Items.InsertObject(TargetIndex, SelectedItems[i], SelectedItems.Objects[i]);
ListBox.Selected[TargetIndex] := True;
inc(TargetIndex);
end;
finally
ListBox.Items.EndUpdate;
end;
finally
SelectedItems.Free;
end;
end;
end;
Now, it is possible to do this with a series of calls to Move
but it's hard to get it right. Each time you make a move all the indices of the selected items change. The approach I give above is my preferred method for solving this problem. Incidentally I recently worked on exactly the same problem in the context of a tree view and it's quite tricky there too!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With