Drag-And-Drop Aplicações Swing em Java – Parte 04

 

Aprenda a usar as classes de Drag-and-Drop do Java Swing através de um exemplo prático.

Por: Francisco Voccio Netto

Lado Drop

Por outro lado, temos a face Drop, que será chamada quando o usuário soltar o botão do mouse.

Para que isso se concretize precisamos desenvolver uma classe que implemente a interface
DropTargetListener.(Listagem 4).

Listagem 4. OuvinteDragSource.java

package br.javamagazine.dnd;

import java.awt.*;
import br.javamagazine.botoes.BotaoImpl;
import br.javamagazine.figuras.Figura;
import br.javamagazine.telas.util.PainelContainer;

 

public class OuvinteLocalDrop implements DropTargetListener {

 

  private PainelContainer painelContainer;

  private GerenciadorDeTransferencia gerenciador;

 

  public OuvinteLocalDrop(PainelContainer painelContainer) {

    this.painelContainer = painelContainer;

    gerenciador = new GerenciadorDeTransferencia();

  }

 

  /**

   * Chamado pelo isDragOk

   * Verifica se a ação do drop é válida

   * @param DropTargetDragEvent o evento

   * @return retorna a condição

   */

  private boolean isDragFlavorSupported(DropTargetDragEvent e) {

    boolean ok = false;

    if (e.isDataFlavorSupported(GerenciadorDeTransferencia.localStringFlavor)) {

      ok = true;

    }

    else if (e.isDataFlavorSupported(DataFlavor.stringFlavor)) {

      ok = true;

    }

    return ok;

  }

 

  /**

   * É chamado pelo dragEnter e o dragOver

   * Também é verificado a ação e as operações    

   * @param O evento drop

   * @return Retorna verdadeiro se o movimento de arrastar

   * está correto

   */

  private boolean isDragOk(DropTargetDragEvent e) {

    if (isDragFlavorSupported(e) == false) { return false; }

 

    int da = e.getDropAction();

 

    // verifica a ação que a area de resposta pode receber

    if ((da & this.painelContainer.obterAcceptableActions()) == 0) { return false; }

    return true;

  }

 

  /**

   * Por onde o evento de arrastar começa

   * chama o acceptDrag ou rejectDrag com base no isDragOk

   */

  public void dragEnter(DropTargetDragEvent e) {

    if (isDragOk(e) == false) {

      e.rejectDrag();

      return;

    }

    e.acceptDrag(e.getDropAction());

  }

 

  /**

   * Depois que o objeto é arrastado

   * chama o acceptDrag ou rejectDrag com base no isDragOk

   */

  public void dragOver(DropTargetDragEvent e) {

 

    if (isDragOk(e) == false) {

      this.painelContainer.mudarCorBorda(Color.RED);

      e.rejectDrag();

      return;

    }

  }

 

  public void dropActionChanged(DropTargetDragEvent e) {

    if (isDragOk(e) == false) {

      e.rejectDrag();

      return;

    }

    e.acceptDrag(e.getDropAction());

  }

 

  public void dragExit(DropTargetEvent e) {

  }

 

  public void drop(DropTargetDropEvent e) {

    DataFlavor escolha = gerenciador.obterNossaOpcao();

 

    if (escolha == null) {

      e.rejectDrop();

      return;

    }

 

    if ((e.getSourceActions() & this.painelContainer.obterAcceptableActions()) == 0)

    {

      e.rejectDrop();

      return;

    }

 

    BotaoImpl botao = null;

    try {

      e.acceptDrop(this.painelContainer.obterAcceptableActions());

      botao = (BotaoImpl) e.getTransferable().getTransferData(escolha);

      if (botao == null) { throw new NullPointerException(); }

    }

    catch (Throwable t) {

      e.dropComplete(false);

      return;

    }

 

    // utiliza a fabrica de figuras conforme o botão selecionado

    Figura figura = botao.obterFigura();

    painelContainer.adicionarFigura(figura, e.getLocation());

  }

}


Esta é uma implementação simples da interface
DropTargetListener, todos os métodos são disponibilizados pela API. O que mais chama a nossa atenção é o método drop pois é ele que é responsável por definir o estado da aplicação após o usuário soltar o botão do mouse.

Reparem que eu chamo novamente nosso gerenciador e obtenho nossa escolha (flavor) como foi definido anteriormente.

Temos também um atributo painelContainer, este como foi definido pelo construtor da nossa classe é o local de destino do nosso objeto que foi arrastado.

Mostrarei uma pequena parte da implementação de como ficará nossa classe PainelContainer (Listagem 5).

Listagem 5. PainelContainer
.java

package br.javamagazine.telas.util;

 

import java.awt.*;

import java.awt.dnd.*;

import javax.swing.JComponent;

import br.javamagazine.dnd.OuvinteLocalDrop;

import br.javamagazine.figuras.Figura;

 

public abstract class PainelContainer extends JComponent {

 

  //todas as inicializações das propriedades (vide projeto)

  private int acceptableActions;

 

  public PainelContainer() {

    this.acceptableActions = DnDConstants.ACTION_COPY_OR_MOVE;

    // component, ops, listener, accepting

    new DropTarget(this, this.acceptableActions, new OuvinteLocalDrop(this),

        true);

  }

 

  public abstract void adicionarComponenteDrag(Figura figura, Point localizacao);

 

  public abstract Boolean removerComponenteDrag(Figura figura);

 

.

. //continuação da classe

.

É importante ressaltar esta parte da implementação, pois por decisão minha defini que esta classe será do tipo JComponent ou seja, nosso editor final irá herdar desta classe.

Toda estrutura do exemplo pode ser observada na Figura 1.

Outra decisão são os métodos abstratos adicionarComponenteDrag e removerComponenteDrag,
sendo assim, quem for estender (no nosso caso o Editor) implementará da forma mais conveniente ( será mostrado em seguida Listagem 6).