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.
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 } }
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.).
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); } }