JComponent Drag n Drop
Einführung
Drag n Drop ist für den Benutzer eine einfache Möglichkeit Daten durch Verschieben schnell zu ordnen.
Da Drag n Drop sehr intuitiv ist und auf der Selbstständigkeit des Benutzers aufbaut, kann es keinen einfachen Ersatz für dieses mächtige Handling geben. Aber genau dieser Punkt ist auch die grösste Schwäche des Drag n Drops: Der Benutzer weiss oftmals nicht, wann oder wo er Daten mit Drag n Drop verschieben kann.
Das Implementieren einer Drag n Drop Komponente mit Java Swing ist im Vergleich zum ihrem Nutzen oftmals sehr aufwändig.
Vorbereitung
Die meisten
JComponents können mit Drag n Drop umgehen.
Diese drei Methoden müssen mit den richtigen Parametern auf der Komponente aufgerufen werden:
setDragEnabled(boolean); |
Schaltet mit true das Drag n Drop für die Komponente ein |
setDropMode(DropMode); |
Der Dropmode bestimmt, wie das Element eingefügt wird |
setTransferHandler(TransferHandler); |
Der TransferHandler wird benötigt um zu bestimmen was während des Drag und Drop Vorganges passiert |
Dropmode
Das sind die vier verschiedenen
DropMode:
DropMode.INSERT |
Fügt das Element an der gewählten Position ein |
DropMode.USE_SELECTION |
Ersetzt das Element in der Liste |
DropMode.ON
|
Ersetzt das Element in der Liste |
DropMode.ON_OR_INSERT |
Ersetzt das Element in der Liste oder fügt es ein (Ctrl-Key relevant) |
Da man in den meisten Drag n Drop Fällen keine vorhandenen Daten ersetzt werden, benutzt man oftmals nur den
DropMode.INSERT.
TransferHandler
Der TransferHandler ist der Schlüssel zum Drag n Drop. Er behandelt das Transferieren von Datentypen zu anderen Komponenten. Auch andere, nicht Java-Programme können mit den gedraggten Inhalten (vor allem vom Typ String) umegehen.
Implementieren der Logik (TransferHandler)
Um einen TransferHandler zu implementieren erstellt man eine Subklasse von
TransferHandler.
Folgender Methoden müssen mindestens überschrieben und implementiert werden:
canImport(TransferSupport)
getSourceAction(JComponent)
importData(TransferSupport)
createTransferable(JComponet)
canImport(TransferSupport)
Während des Drag-Vorganges wird diese Methode wiederholt aufgerufen und bestimmt mit einem boolean als Rückgabewert ob ein Drop möglich ist. Dabei wird auch der Cursor angepasst.
An dieser Stelle kann getestet werden ob das gedragte Element den Anfroderungen/Data-Flavor (in diesem Beispiel ein String-Typ) entspricht:
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
getSourceAction(JComponent)
Als Rückgabewert gibt man in dieser Methode an, welche Operation auf der Quelle (
JComponent), erlaubt ist.
Entsprechend der Operation, wird auch der Cursor angepasst.
Es gibt folgende Operations-Möglichkeiten:
TransferHandler.NONE
|
Kein Transfer der Daten
|
TransferHandler.COPY |
Kopiert die Daten |
TransferHandler.MOVE |
Verschiebt die Daten |
TransferHandler.COPY_OR_MOVE |
Verschiebt die Daten, oder Kopiert sie wenn die CTRL-Taste gedrückt ist |
TransferHandler.LINK |
Verlinkte Daten |
Hier ein Code-Beispiel:
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
importData(TransferSupport)
Wenn ein Drop erfolgreich war wird diese Methode aufgerufen.
Bei Kopiervorgängen muss wahrscheinlich nicht viel in dieser Methode stehen. Wenn ein Element jedoch auf der alten Komponente entfernt wird, muss das transferierte Element aus dieser Komponente gelöscht werden. Auch eine Neu-Selektierung der verbliebenen Elemente wäre in diesem Fall angebracht.
- In diesem Beispiel wird die neue Position des Elementes in eine JList berechent.
- Über ein Transferable-Objekt kann das transferierte Element bezogen werden.
- Dieses Element wird der nun innerhalb der ursprünglichen JList verschoben (move-Methode wurde selber implementiert) und danach neu selektiert.
public boolean importData(TransferSupport transferInfo) {
if (!transferInfo.isDrop()) {
System.out.println("Element wurde nicht transferiert!");
return false;
}
JList.DropLocation dropLocation = (JList.DropLocation)transferInfo.getDropLocation();
int index = dropLocation.getIndex();
Transferable transferable = transferInfo.getTransferable();
String data;
try {
data = (String)transferable.getTransferData(DataFlavor.stringFlavor);
}
catch (Exception e) { return false; }
JList list = (JList)transferInfo.getComponent();
ListModel listModel = (ListModel)list.getModel();
int rangedIndex = listModel.move(data, index);
list.getSelectionModel().setSelectionInterval(0, rangedIndex);
return true;
}
createTransferable(JComponet)
In dieser Methode wird das transferierte Element herausgesucht, in ein Transferable-Objekt gekappselt und zurückgegeben.
Dieses sehr simple Beispiel zeigt, wie man ein selektiertes Element (entspricht dem transferierten Element) aus einer JList bekommt. Dieses String-Element wird danach in einer StringSelection gekappselt und als Rückgabewert verwendet:
protected Transferable createTransferable(JComponent dragList) {
JList list = (JList)dragList;
String selectedValue = (String)list.getSelectedValue();
return new StringSelection(selectedValue);
}
Zusammenfassung
Es gibt kein allgemein gültiges Rezept wie Drag n Drop auf einer Komponente aktiviert werden soll. Es ist sehr wichtig zu verstehen, dass Drag n Drop sehr vielseitig eingesetzt werden kann, zum Beispiel mit Multiselect, dem Kopieren und Verschieben etc. Deshalb ist die Implementierung des TransferHandlers immer eigen.
Literatur