Weitere aktuelle Java-Titel finden Sie bei dpunkt.
 Inhaltsverzeichnis   Auf Ebene Zurück   Seite Zurück   Seite Vor   Auf Ebene Vor   Eine Ebene höher   Index


8.7.6

Drag-and-Drop



Seit der Version [1.4]1.4 kann man bei Swing-Komponenten Drag-and-Drop sehr einfach mit Hilfe der Methode setDragEnabled(boolean value) aktivieren.

Dabei bezieht sich die Aktivierung nur auf den Lieferanten - die Komponenten, die nicht aktiviert wurden, können jederzeit die verschobenen Daten aufnehmen. Welche Komponenten Drag-and-Drop unterstützen ist in folgender Tabelle aufgeführt:

Bei Swing-Komponenten, die von Natur aus kein Drag-and-Drop unterstützen, wie beispielsweise JLabel, kann man dies seit der Version [1.4]1.4 durch folgenden Code nachprogrammieren:

  JLabel label = new JLabel();
  label.setTransferHandler(new TransferHandler("text"));
  label.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      JComponent c = (JComponent)e.getSource();
      TransferHandler th = c.getTransferHandler();
      th.exportAsDrag(c, e, TransferHandler.COPY);
    }
  });
Das Entscheidende ist dabei der String des Konstruktors der Klasse TransferHandler. Hierbei handelt es sich um eine JavaBeans-Property, so dass hier das zu transferierende Objekt mittels der get-Methode »getText« geholt bzw. über die Setter-Methode »setText« gesetzt wird.

Tabelle 8.4: Einfache Unterstützung von Drag-and-Drop der Swing-Standardkomponenten seit der Version 1.4
KomponenteUnterstützt DragUnterstützt Drop
JColorChooserXX
JEditorPaneXX
JFileChooserX 
JFormattedTextFieldXX
JLabel  
JListX 
JPasswordField X
JTableX 
JTextAreaXX
JTextFieldXX
JTextPaneXX
JTree X

java.awt.dnd.DropTarget

Möchte man mehr Kontrolle über den Drag-and-Drop-Vorgang erhalten bzw. steht nur eine ältere Version von Java zur Verfügung, kann man über die Packages java.awt.datatransfer und java.awt.dnd die nötigen Klassen einbinden.

Wie beim Copy-and-Paste werden die Daten mit Hilfe des Transferable-Interfaces ausgetauscht.

Wenn man nur auf das »Fallenlassen« reagieren möchte, benötigt man ein DropTarget. Dieses initialisiert man mit der Komponente, die das Ziel darstellt und einem DropTargetListener. Dieses Interface definiert die folgenden Methoden:

Besonders wichtig ist hierbei die Methode drop. In dieser Methode muss entschieden werden, was mit dem übertragenen Objekt gemacht werden soll. Entweder es wird übernommen oder zurückgewiesen.

Der Ablauf ist dabei folgender:

Hat man eine Komponente, die aus vielen unterschiedlichen Bereichen (wie ein Baum oder eine Tabelle) besteht, möchte man vielleicht, dass nur an bestimmten Bereichen ein Fallenlassen erlaubt ist. Zu diesem Zweck kann man in den Methoden dragEnter und dragOver entweder die Methode DropTargetDragEvent.acceptDrop(int dropAction) oder DropTargetDragEvent.rejectDrop() aufrufen, je nachdem, ob an der Stelle ein Fallenlassen erlaubt ist oder nicht. Dies wird meist an der Position der Maus (DropTargetDragEvent.getLocation()) innerhalb der Komponente bestimmt.

Wenn man dem Benutzer nicht die Wahl lassen möchte, ob er das Objekt verschieben, kopieren oder verknüpfen darf, dann muss lediglich die entsprechende dropComplete()-Methode mit einem der folgenden Werte gefüllt werden: DnDConstants.ACTION_COPY, DnDConstants.ACTION_COPY_OR_MOVE, DnDConstants.ACTION_LINK, DnDConstants.ACTION_MOVE. Wer keine Vorgaben machen möchte, kann die aktuelle Aktion mittels DropTargetDragEvent.getDropAction() beibehalten.
label = new JLabel();
DropTargetListener dropTargetListener =
 new DropTargetListener() {

  // Die Maus betritt die Komponente mit
  // einem Objekt
  public void dragEnter(DropTargetDragEvent e) {}

  // Die Komponente wird verlassen 
  public void dragExit(DropTargetEvent e) {}

  // Die Maus bewegt sich über die Komponente
  public void dragOver(DropTargetDragEvent e) {}

  public void drop(DropTargetDropEvent e) {
    try {
      Transferable tr = e.getTransferable();
      DataFlavor[] flavors = tr.getTransferDataFlavors();
      for (int i = 0; i < flavors.length; i++)
       if (flavors[i].isFlavorJavaFileListType()) {
        // Zunächst annehmen
        e.acceptDrop (e.getDropAction());
        List files = (List) tr.getTransferData(flavors[i]);
        // Wir setzen in das Label den Namen der ersten 
        // Datei
        label.setText(files.get(0).toString());
        e.dropComplete(true);
        return;
       }
    } catch (Throwable t) { t.printStackTrace(); }
    // Ein Problem ist aufgetreten
    e.rejectDrop();
  }
   
  // Jemand hat die Art des Drops (Move, Copy, Link)
  // geändert
  public void dropActionChanged(
         DropTargetDragEvent e) {}
};
DropTarget dropTarget = new DropTarget(
  label, dropTargetListener);

java.awt.dnd.DragSource

Um eine Komponente als Quelle eines Drag-and-Drop-Vorganges zu verwenden, muss ein Exemplar der Klasse DragSource initialisiert werden.

Mit createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl) kann die entsprechende Quell-Komponente, die beabsichtigte Aktion und der Listener für den Start eines Drag-Events registriert werden.

Das Interface DragGestureListener besitzt nur die Methode

  public void dragGestureRecognized(DragGestureEvent dge)

Diese Methode wird aufgerufen, wenn der Benutzer bei gedrückter Maustaste den Mauszeiger bewegt. Ob dadurch ein Drag-and-Drop initiiert ist, wird in der Methode entschieden. Falls ja, wird die Methode startDrag() in dem DragGestureEvent-Exemplar aufgerufen. Hierbei gibt es verschiedene Signaturen. Pflicht ist die Angabe eines Cursors (aufgrund des Bugs #4407521 bei den Java Versionen 1.3.1 und 1.4 sollte der Wert hier null sein) und des Transferable, welches die Daten enthält. Zusätzlich kann eine Grafik angegeben werden, die beim Drag-and-Drop angezeigt wird , und ein DragSourceListener. Es ist zu beachten, dass Windows keine eigenen Grafiken unterstützt.

  DragGestureListener dragGestureListener =
    new DragGestureListener() {
     public void dragGestureRecognized(
       DragGestureEvent e) {
       // Der Text des Label soll
       // JVM-intern
       // übertragen werden
       StringSelection selection = 
         new StringSelection(
          label.getText()); 
       e.startDrag(null, selection, selection);
     } 
  };
  DragSource dragSource = new DragSource();
  DragGestureRecognizer dgr = 
    dragSource.createDefaultDragGestureRecognizer(
    label, 
    DnDConstants.ACTION_COPY, 
    dragGestureListener);

java.awt.dnd.DragSourceListener

Über das Interface DragSourceListener kann die Quelle eines Drag-and-Drop-Vorganges über den Verlauf informiert werden. Dies ist besonders dann interessant, wenn nach einem erfolgreichen Drag-and-Drop-Vorgang das verschobene Objekt gelöscht werden muss.

Hierzu wird die Methode dragDropEnd(DragSourceDropEvent e) benutzt, die aufgerufen wird, wenn ein Drag-and-Drop beendet wurde. Wurden beispielsweise Dateien verschoben, so werden diese durch folgenden Code gelöscht:

  public void dragDropEnd (DragSourceDropEvent e) {
   if (e.getDropSuccess() && 
       e.getDropAction() == DnDConstants.ACTION_MOVE) {
     Transferable tr = e.getDragSourceContext().
                       getTransferable();
     DataFlavor[] flavors = tr.getTransferDataFlavors();
     for (int i = 0; i < flavors.length; i++)
       if (flavors[i].isFlavorJavaFileListType()) 
         try {
           List files = (List) tr.getTransferData(flavors[i]);
           for (int j = 0; j < files.size (); j++)
             ((File) files.get(j)).delete();
         } catch (Throwable t) { t.printStackTrace (); }
   }
  }

java.awt.dnd.Autoscroll

Wenn die Zielkomponente in einem JScrollPane liegt und dann der Mauszeiger an den Rand des sichtbaren Bereiches stößt, möchte man meist, dass der dabei bisher verdeckte Bereich sichtbar gemacht wird. Zu diesem Zweck muss die entsprechende Komponente das Interface Autoscroll implementieren. Eine zusätzliche Registrierung der Komponente ist hierbei nicht nötig.

Seit der Version [1.4]1.4 kann man bei Swing-Komponenten dafür die Methode setAutoscrolls(boolean flag) benutzen.

Vor der Version 1.4 wird dafür das Interface Autoscroll benötigt. Dieses definiert zwei Methoden:


 Inhaltsverzeichnis   Auf Ebene Zurück   Seite Zurück   Seite Vor   Auf Ebene Vor   Eine Ebene höher   Index

Copyright © 2002 dpunkt.Verlag, Heidelberg. Alle Rechte vorbehalten.