Delphi listbox перетаскивать несколько элементов - PullRequest
3 голосов
/ 07 февраля 2012

Мне нужно перетащить несколько элементов внутри моего Tlistbox.
Код, на который я ссылаюсь:

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; 

отсюда .
Этоработает нормально, но мне нужно добиться вот что: enter image description here.

Почему я хочу это, потому что существует определенный порядок, который соответствует этим элементам списка.Поэтому вместо того, чтобы вручную выбирать каждый элемент и перетаскивать его, я хочу включить несколько перетаскиваний.

Любые мнения о том, как я могу добиться этого, приветствуются.
Также можно предложить использовать другие компоненты, если следующее возможно с использованием того же самого.

1 Ответ

6 голосов
/ 07 февраля 2012

Это на удивление сложно сделать хорошо (см. Мою первую редакцию этого ответа, чтобы узнать, как ошибиться).

Вот довольно простой для понимания подход, который решает проблему следующим образом:

  1. Удаление всех выбранных элементов из списка и сохранение их во временном списке строк.
  2. Повторное добавление элементов в список, начиная с целевого индекса.
  3. Re-выбирает каждый повторно добавленный элемент.

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;

Теперь это можно сделать с помощью серии вызовов на Move, но сложно сделать это правильно,Каждый раз, когда вы делаете ход, все индексы выбранных элементов меняются.Подход, который я привел выше, является моим предпочтительным методом решения этой проблемы.Кстати, недавно я работал над точно такой же проблемой в контексте древовидного представления, и это тоже довольно сложно!

...