Проблемы с перетаскиванием списка при включенном множественном выборе
-
08-07-2019 - |
Вопрос
У меня есть TListBox с multiselect и ExtendedSelect, для обоих установлено значение true.Мне нужно иметь возможность перетаскивать несколько элементов в списке, чтобы переупорядочить их.Моя проблема заключается в том, что происходит, когда пользователь нажимает на элемент, который уже выбран, не удерживая нажатой клавишу CTRL или SHIFT.
Случай 1:Режим перетаскивания установлен в dmManual Выделение будет удалено до того, как мышь будет нажата.Это не позволит перетаскивать несколько элементов.
Случай 2:Для параметра DragMode установлено значение dmAutomatic Событие MouseDown никогда не срабатывает.Выделение не очищено, поэтому перетаскивание выполняется нормально, но пользователь не может очистить выделение, щелкнув по одному из выбранных элементов.Это действительно вызывает проблему, если выбраны все элементы или следующий элемент, который пользователь хочет выбрать, был частью текущего выбора.
Обратите внимание, что эта проблема возникает только в том случае, если вы назначаете что-либо DragObject в процедуре OnStartDrag.Я думаю, проблема исчезла бы, если бы OnStartDrag запускался только после того, как пользователь перемещал мышь.У меня есть мышь.Установлено значение DragImmediate: = false, но я все равно запускаю startDrag, как только нажимаю на элемент в списке.
Я использую Delphi 7 для этого проекта, но я вижу такое же поведение в Delphi 2007.
Решение 4
Я не уверен, почему это имеет значение, но если я изменю DragObject на TDragКонтрольObjectEx (вместо TDR-gobjectex) я получаю поведение, которое я ищу.Режим перетаскивания установлен на Автоматический.
Я попытался разобраться, на что это влияет, но так и не смог в этом разобраться.
Другие советы
Я некоторое время играл с этим.И наблюдайте те же эффекты.
Я бы использовал Case2 и добавил кнопку (Выбрать все / Отменить выбор всего) в список.Это даже добавляет дополнительную функциональность и решает самую неприятную часть проблемы.
Используйте вариант 2 и при срабатывании события TListBox.OnMouseUp проверьте, были ли выбраны и перетаскивались ли несколько элементов.Если выбрано несколько элементов, но они не были перетащены, то отмените выбор всех элементов, кроме выбранного элемента.
Я бы использовал этот метод, потому что проводник Windows работает именно так.
Немного запутанно, но это работает.Режим перетаскивания в списке имеет значение dmAutomatic.
procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
iDropIdx, i: Integer;
pDropPoint: TPoint;
slSelected: TStrings;
begin
{Which item is being dropped onto?}
pDropPoint := Point(X, Y);
iDropIdx := ListBox1.ItemAtPos(pDropPoint, False);
slSelected := TStringList.Create;
try
{Copy the selected items to another string list}
for i := 0 to Pred(ListBox1.Items.Count) do
begin
if (ListBox1.Selected[i]) then
slSelected.Append(ListBox1.Items[i]);
end;
{Find the selected items in the listbox and swap them with the drop target}
for i := 0 to Pred(slSelected.Count) do
begin
ListBox1.Items.Exchange(ListBox1.Items.IndexOf(slSelected[i]), iDropIdx);
inc(iDropIdx);
end;
finally
slSelected.Free;
end;
end;