next up previous
Next: Applet-Besonderheiten Up: dragndrop Previous: Transferables

Unterabschnitte

Drag'n'Drop API

Draggable Component

Im Package java.awt.dnd gibt es verschiedene Klassen. Die DnDConstants definieren Integer-Konstanten für die verschiedenen Drag'n'Drop-Aktionen wie Copy, Move oder Link. Cursor dafür werden von der DragSource als statische Variablen bereitgestellt.

Die Quelle einer Dragaktion sollte mit java.awt.dnd.DragSource, java.awt.dnd.DragGestureRecognizer, java.awt.dnd.DragGestureListener, java.awt.datatransfer.Transferable und java.awt.dnd.DragSourceListener assoziiert sein. Eine DragSource bekommt man mit public static DragSource.getDefaultDragSource, diese hält für die Lebensdauer der JVM. Ein DragGestureRecognizer kuemmert sich um verschiedene Drags (Copy, Link, Move) und wie sei auf verschiedenen Plattformen begonnen werden (Mac, Motif, Win32). Mit dragSource.createDefaultDragGestureRecognizer(Component, Aktion, Listener) wird ein neuer DragGestureRecognizer zur Verfügung gestellt. Mit Hilfe der dragGestureRecognized-Methode gibt dieser an den DragGestureListener weiter, wann und was für ein Drag gestartet wurde.

Die beiden Interfaces DragGestureListener und DragSourceListener muss man selbst implementieren. Wenn der DragGestureListener benachrichtigt wurde, überprüft er das Event, ob auch ein Drag gestartet wurde, der erlaubt ist, holt sich die zugehörigen Daten und verpackt sie in eine Transferable, die dann in startDrag gesteckt wird.

Ein DragSourceListener hat die Methoden dragEnter, dragExit und dragOver, wo man z. B. das Aussehen des Cursors verändern kann. Unter nicht-Win32-Systemen kann man auch eigene Bilder für den Cursor verwenden. Die Methode dropActionChanged wird aufgerufen, wenn sich die Drop-Aktion verändert hat - der User hat z. B. mit Control und Maus angefangen zu draggen und dann Control losgelassen. So kann man überprüfen, ob das Draggen dann noch erlaubt ist.

Am Ende des Drags wird dragDropEnd aufgerufen - das dazugehörige Event kann man dann mit getDropSuccess() nach dem Erfolg des Drags fragen und z. B. bei Move das gedraggte Objekt löschen.

Codebeispiel:

class DGListener implements DragGestureListener{
      
      public void dragGestureRecognized(DragGestureEvent dge){ // los, drag!
          try{
            Transferable t = getTransferableAt(DnDList.this.getSelectedIndex());
            dragSource.startDrag(dge, okCursor, t, sourceListener);
          }
          catch(InvalidDnDOperationException e){
            e.printStackTrace();
          }
      }
    }

    class DSListener implements DragSourceListener{
      
      public void dragEnter(DragSourceDragEvent dse){ //darf das hierlang?
          DragSourceContext context = dse.getDragSourceContext();
          int action = dse.getDropAction();
          if((action & accept) == 0){ //falsche Aktion
            context.setCursor(noCursor);
          }
          else{
            context.setCursor(okCursor);
          }
      }

      public void dragOver(DragSourceDragEvent dse){ // oder hierdrueber
          dragEnter(dse);
      }
      
      public void dragExit(DragSourceEvent dse){ // raus gehts
      }

      public void dragDropEnd(DragSourceDropEvent dse){ // drag ist mit drop zuende
          if(dse.getDropSuccess() == false){//drop tat nicht
            return;
          }
          int action = dse.getDropAction(); 
          if((action & accept) == 0){ // falsche Aktion
            return;
          }
          try{
            Object data = dse.getDragSourceContext().getTransferable().getTransferData(localFlavor);
            if(data == null ||!(data instanceof String)){
                return;
            }
            removeItem(data); // das gedroppte hier loeschen
          }
          catch(Throwable t){
            t.printStackTrace();
          }
      }

      public void dropActionChanged(DragSourceDragEvent dse){ //z.B. ctrl loslassen
          dragEnter(dse); //ueberpruefen
      }
    }

Droppable Component

Eine Droppable Component sollte mit einem java.awt.dnd.DropTarget und einem java.awt.dnd.DropTargetListener assoziiert sein. Das DropTarget wird einfach mit der Component, den Aktionen und dem Listener erzeugt.

Der Listener braucht eine Assoziation mit einer Component für dragUnder-Effekte bei dragEnter, dragOver und dragExit. In drop geschieht dann der Drop: es wird abgecheckt, ob der Drop auch erlaubt ist, dann wird die Transferable geholt, evtl. anhand des DataFlavors nochmal auf Verwendbarkeit überprüft und dann werden die Daten benutzt (eingefügt / gelinkt etc.).

Codebeispiel

 
class DTListener implements DropTargetListener{
      
      public void dragEnter(DropTargetDragEvent e){ //darf man hierher draggen?
          if(isDragOK(e) == false){
            e.rejectDrag(); //elegant
            return;
          }
          e.acceptDrag(accept); //das auch
      }
      public void dragExit(DropTargetEvent e){ //drag vorbei
      }

      public void dragOver(DropTargetDragEvent e){//drueber wird gedraggt
          if(isDragOK(e) == false){
            e.rejectDrag();
            return;
          }
          e.acceptDrag(accept);
      }

      public void drop(DropTargetDropEvent e){ //drop
          Object data;
          if((data = validateDrop(e)) == null){ //nix ok
            e.rejectDrop(); //ich habe fertig
            return;
          }
          e.acceptDrop(accept); //doch ok
          if(!doTheDrop(e, data)){  //aber hat trotzdem nicht geklappt
            e.dropComplete(false); //also nicht vorbei
            return;
          }
          e.dropComplete(true); //hier doch
      }

      public void dropActionChanged(DropTargetDragEvent e){ //wieder ctrl losgelassen
          if(isDragOK(e) == false){
            e.rejectDrag();
            return;
          }
          e.acceptDrag(accept);
      }

    }

Grafische Darstellung des Event-Flusses

Abbildung 2: Der Event-Fluss beim Drag'n'Drop
\includegraphics[angle=0,width=16cm]{pic2.eps}


next up previous
Next: Applet-Besonderheiten Up: dragndrop Previous: Transferables
Britta Koch
1999-11-29