Técnicas de drag-and-drop

Veja nesse artigo de Adriano Santos, como implementar o drag and drop em componentes como ListBox, Animate e DBGrid.

Um dos recursos mais utilizados no Windows certamente é o Drag-and-Drop que significa arrastar-e-soltar. Em toda minha experiência com programação vejo pouca utilização deste recurso em aplicações Delphi e muitas dúvidas em fóruns, por isso elaborei alguns exemplos para entendermos melhor como funciona este recurso.

Entendendo a lógica

O recurso de drag-and-drop é ativado partindo do evento onMouseDown do controle Origem. É nele que iniciamos a operação usando o método BeginDrag do objeto. A finalização do arrasto é controlada pelo evento onEndDrag também do objeto Origem.

No objeto Destino usamos os eventos onDragOver para descobrirmos se o Source (objeto Origem) é o objeto esperado e assim aceitar a ação. Ainda no objeto Destino, no evento onDragDrop, ou seja, quando o usuário soltar o mouse sobre o objeto, chamamos novamente o evento onEndDrag do objeto Origem passando o parâmetro True. Isso fará com que a ação seja finalizada. Vamos desenvolver um exemplo prático pra que fique mais claro.

1º Exemplo: Arrastando um TAnimate

Nosso primeiro exemplo é bastante simples. Insira um TListBox, um TPanel e dentro do TPanel um TAnimate. No TListBox insira os seguintes valores na propriedade Items:

Como o componente TAnimate não possui os eventos onDragOver e onDragDrop, vamos usar o TPanel como “controlador”, ou seja, ele que receberá o arrasto e definirá o novo AVI do componente e o porá em execução.

No evento onMouseDown do ListBox (neste exemplo deu-se o nome de LstAvi) digite o algoritmo da Listagem 1. Este algoritmo verifica se o objeto (Sender) é o LstAvi e ainda se o botão esquerdo do mouse está pressionado. Em caso positivo, dá início ao processo de drag chamando o método BeginDrag.

Listagem 1. Evento onMouseDown do LstAvi (ListBox)

procedure TFrmDragDrop.LstAviMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Sender = LstAvi) and (Button = mbLeft) then LstAvi.BeginDrag(False); // inicia a operacao end;

Agora vamos mexer com o nosso TPanel. Em seu evento onDragDrop vamos fazer uma simples verificação. Se o Source (objeto origem) for o LstAvi então chamamos o método EndDrag, bem simples, como mostra a Listagem 2.

Listagem 2. Evento onDragDrop do Panel

procedure TFrmDragDrop.Panel1DragDrop(Sender, Source: TObject; X, Y: Integer); begin if Source = LstAvi then LstAvi.EndDrag(True); // finaliza o processo end;

Ainda no TPanel, porém agora no evento onDragOver, faremos outra verificação para aceitar ou não a ação. Se o objeto Origem (Source) for LstAvi então aceitamos: Accept := True, como mostra a Listagem 3.

Listagem 3. Evento onDragOver do Panel

procedure TFrmDragDrop.Panel1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin if Source = LstAvi then Accept := True; // aceita a ação end;

Pra finalizar este primeiro exemplo, basta programarmos o evento onEndDrag do LstAvi fazendo com que o mesmo mude o avi do TAnimate e ative-o.

Para isso verificamos se o alvo (Target) é diferente de Nil, nos informando que houve uma chamada ao evento por outro componente, assim sendo comandamos as ações que trocam o avi e ativam-o. Veja como fica na Listagem 4.

Listagem 4. Evento onEndDrag do LstAvi

procedure TFrmDragDrop.LstAviEndDrag(Sender, Target: TObject; X, Y: Integer); begin if Target <> nil then begin if Animate1.CommonAVI <> aviNone then Animate1.Stop; Animate1.CommonAVI := TCommonAVI(LstAvi.ItemIndex); if Animate1.CommonAVI <> aviNone then Animate1.Play(Animate1.StartFrame, Animate1.StopFrame, 0); end; end;

2º Exemplo: Trocando itens entre ListBox

Nosso segundo exemplo é um pouco mais trabalhoso, mas segue a mesma lógica aplicada no exemplo anterior. Vamos “trocar” de lugar os itens de dois ListBox, ou seja, poderemos arrasta-los de um lado para o outro.

Para este exemplo precisaremos apenas de dois listbox em tela com os nomes de ListaOrigem e ListaDestino.

Em cada listbox usaremos os eventos onMouseDown, onEndDrag, onDragOver e onDragDrop. Pra facilitar nossa vida, faremos um typecast nos eventos para identificar quem está sendo Origem e Destino em cada evento, desviando desta forma nosso fluxo de programação tornando os eventos genéricos.

Começaremos pelo ListaOrigem no evento onMouseDown. A dica é simples: basta verificar se o Sender é o ListaOrigem ou ListaDestino e assim chamar o método BeginDrag do TListBox, como mostra a Listagem 5.

Listagem 5. Evento onMouseDown do ListaOrigem (ListBox)

procedure TFrmDragDrop.ListaOrigemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Button = mbLeft) and ((Sender = ListaOrigem) or (Sender = ListaDestino)) then TListBox(Sender).BeginDrag(False) // inicia a operacao end;

No evento onDragOver da ListaOrigem faremos o “aceite” da ação, como mostra a Listagem 6.

Listagem 6. Evento onDragOver

procedure TFrmDragDrop.Panel1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin if (Source = ListaOrigem) or (Source = ListaDestino) then Accept := True end;

Seguindo a mesma linha de raciocínio chamamos o método EndDrag no evento onDragDrop, como mostra aListagem 7.

Listagem 7. Evento onDragDrop

procedure TFrmDragDrop.Panel1DragDrop(Sender, Source: TObject; X, Y: Integer); begin if (Source = ListaOrigem) or (Source = ListaDestino) then TListBox(Sender).EndDrag(True); end;

Pra fechar o segundo exemplo basta agora programar a parte mais importante, o evento onEndDrag. Neste caso basta verificar se o alvo é diferente de Nil e então usar o método MoveSelection do componente TListBox, assim como mostra a Listagem 8.

Listagem 8. Evento onEndDrag

procedure TFrmDragDrop.LstAviEndDrag(Sender, Target: TObject; X, Y: Integer); begin if Target <> nil then // trata o fim de uma operacao que foi aceita TListbox(Sender).MoveSelection(TListBox(Target)); end;

Note que em nenhum momento trabalhamos os eventos da ListaDestino, certo? Bom, agora basta associar os eventos onMouseDown, onEndDrag, onDragOver e onDragDrop do ListaDestino aos respectivos eventos de ListaOrigem.

3º Exemplo: Drag-and-drop X DBGrid

Para treinarmos ainda mais o recurso este terceiro exemplo mostra como usar o drag-and-drop com DBGrid. Vamos “trazer” o título da coluna do dbgrid para um Edit.

Precisaremos de: um DBGrid, um Table, um DataSource e um Edit. Ligue o Table da tabela Animals do aliás DBDEMOS. Ligue também o DataSource e o DBGrid.

A programação segue a mesma linha anterior, portanto não entrarei em detalhes. A listagem 9 mostra os eventos onMouseDown e onEndDrag do DBGrid e também onDragDrop e onDragOver do Edit1.

A única alteração em relação aos dois últimos exemplos é que precisamos pegar o título da coluna que o usuário arrastou para o Edit1. Para isso declare a variável Titulo pública para que possamos enxergá-la em toda unit (Listagem 10).

No evento onTitleClick do DBGrid atualizamos a variável Titulo com o nome da coluna. (Listagem 11).

Listagem 10. Eventos do DBGrid

procedure TFrmDragDrop.DBGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Sender = DbGrid1) and (Button = mbLeft) then DbGrid1.BeginDrag(False); // inicia a operacao< end; procedure TFrmDragDrop.DBGrid1EndDrag(Sender, Target: TObject; X, Y: Integer); begin if Target <> nil then Edit1.Text := Titulo; end; procedure TFrmDragDrop.Edit1DragDrop(Sender, Source: TObject; X, Y: Integer); begin if Source = DbGrid1 then DbGrid1.EndDrag(True); // comanda o final da operacao end; procedure TFrmDragDrop.Edit1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin if Source = DbGrid1 then Accept := True; // aceita se vier da lista end;

Listagem 11. Evento onTitleClick do DBGrid

procedure TFrmDragDrop.DBGrid1TitleClick(Column: TColumn); begin Titulo := Column.FieldName; end;

Bem, com isso finalizamos esta bateria de exemplos sobre Drag-and-drop.

Conclusões

Nestes exemplos vimos como é fácil trabalhar com um dos recursos mais utilizados nas interfaces para Windows. O drag-and-drop é útil em diversas ocasiões e ajuda na produtividade do sistema.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados