TListBox Arraste e problemas de gota com MultiSelect habilitado
-
08-07-2019 - |
Pergunta
Eu tenho um TListBox com multiselect e ExtendedSelect ambos conjunto para true. Eu preciso ser capaz de arrastar vários itens na caixa de lista para re-organizar-los. Meu problema é o que acontece quando o usuário clica em um item que já está selecionados sem mantendo pressionada a tecla CTRL ou SHIFT.
Caso 1: DragMode está definida para dmManual A seleção é limpa antes do baixo mouse. Isso não vai permitir que vários itens a ser arrastado.
Caso 2: DragMode está definida para dmAutomatic O evento MouseDown nunca dispara. A seleção não é limpo por isso arrastando é OK, mas o usuário não pode limpar a seleção clicando em um dos itens selecionados. Isso realmente causa um problema se todos os itens estão selecionados ou o próximo item que o usuário deseja selecionar fez parte da seleção atual.
Note que este problema só acontece se você atribuir algo para o DragObject no procedimento OnStartDrag. Acho que o problema iria embora se OnStartDrag só iria começar depois que o usuário move o mouse. Eu tenho Mouse.DragImmediate: = false set, mas eu ainda obter o startDrag disparou assim que eu clicar em um item na caixa de listagem
.Eu estou usando Delphi 7 para este projeto, mas eu vejo o mesmo comportamento em Delphi 2007.
Solução 4
Eu não sei por que isso faz a diferença, mas se eu mudar o DragObject ser um TDrag Controle ObjectEx (em vez de um TDragObjectEx) recebo o comportamento que eu estou procurando. modo de arrastar será definido como Automático.
Eu tentei olhar e ver o que isso estava afetando, mas eu não conseguia entender.
Outras dicas
Eu tenho jogado com isso por um tempo. E observar os mesmos efeitos.
Gostaria de usar Case2 e adicionar um botão (Selecionar Tudo / Desmarcar Tudo) à lista. Ele ainda acrescenta funcionalidade extra e resolve a parte mais chata do problema.
Caso de Uso 2 e quando o evento é acionado TListBox.OnMouseUp verificar para ver se vários itens são selecionados e foram arrastados. Se vários itens são selecionados, mas não foram arrastados, em seguida, desmarque todos os itens além do item clicado.
Gostaria de usar este método porque o Windows Explorer funciona desta forma.
Um pouco de um truque, mas isso funciona. DragMode na caixa de listagem é definida para 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;