Langsam verzweifle ich mit dem Drag&Drop.
Folgende Anforderungen: Es sollen einzelne Zellen in einer JTable per D&D verschoben werden können.
Also habe ich eine JTable, bei der wird folgendes zur Initiallisierung aufgerufen:
handler ist mein TransferHandler, zu dem komme ich gleich. DataUnit ist die Klasse der Objekte, die in der JTable zu liegen kommen, die haben einen eigenen Renderer. Da diese Elemente alle gleiche Größe haben und sich die Zellen nicht in der Größe ändern sollen, wird das in den letzten drei Zeilen auch so festgenagelt.
Mein TransferHandler sieht nun so aus:
Nur Move, denn ich will die Objekte VERSCHIEBEN, nicht kopieren, aber das ist schon das erste, das nicht funktioniert. Beim Drop bleibt nämlich die SourceUnit einfach liegen, ich habe jetzt zweimal das identische Objekt in der JTable.
Das erzeugt eine Wrapper-Klasse um meine eigentliche DataUnit, aber die DataUnit das Transferable-Interface implementieren zu lassen hat genauso gut funktioniert.
canImport ist soweit klar.
Jetzt wird es wieder spannend.
Da drin passiert nun folgendes: Ich besorge mir erstmal den Ort des Drop (Teil 1), dann das Objekt, das verschoben werden soll (Teil 2) und im Teil 3 besorge ich mir das was in der Drop-Location liegt und falls da was ist, kombiniere ich das mit dem was fallengelassen wird. Ansonsten wird einfach das Objekt dort abgelegt.
Mein Problem: Obwohl ich als SourceAction ausdrücklich nur MOVE zulasse, wird die Zelle am Ausgangspunkt des D&D nicht geleert. Um das zu gewährleisten habe ich folgendes gemacht:
D.h. beim Aufnehmen wird die Quell-Zelle geleert. Das sieht zwar auf den ersten Blick ok aus, aber wenn der Drag abgebrochen wird, ist das Objekt weg. Wenn der D&D außerhalb der JTable endet, dann genauso.
Deswegen meine Frage: Hat jemand ein Beispiel, wie D&D von Zellen in einer JTable richtig implementiert werden? Ich suche mir seit Tagen die Finger wund, ich finde nichts brauchbares. Oder kann mir bitte jemand unter die Arme greifen und ein paar Tips geben?
Das zweite Problem stelle ich erstmal zurück. Es geht dabei darum, daß während des Drags kein Symbol angezeigt wird und ich habe nicht herausgefunden, wie ich es anstelle, daß man eine visuelle Rückmeldung bekommt, daß gerade ein D&D in Aktion ist.
Folgende Anforderungen: Es sollen einzelne Zellen in einer JTable per D&D verschoben werden können.
Also habe ich eine JTable, bei der wird folgendes zur Initiallisierung aufgerufen:
Java:
setDragEnabled( true );
setDropMode( DropMode.USE_SELECTION );
setTransferHandler( handler );
setDefaultRenderer( DataUnit.class, new DataUnitRenderer() );
setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
setCellSelectionEnabled( true );
setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
getTableHeader().setResizingAllowed( false );
getTableHeader().setReorderingAllowed( false );
handler ist mein TransferHandler, zu dem komme ich gleich. DataUnit ist die Klasse der Objekte, die in der JTable zu liegen kommen, die haben einen eigenen Renderer. Da diese Elemente alle gleiche Größe haben und sich die Zellen nicht in der Größe ändern sollen, wird das in den letzten drei Zeilen auch so festgenagelt.
Mein TransferHandler sieht nun so aus:
Java:
public int getSourceActions( JComponent c ) {
return DnDConstants.ACTION_MOVE;
}
Nur Move, denn ich will die Objekte VERSCHIEBEN, nicht kopieren, aber das ist schon das erste, das nicht funktioniert. Beim Drop bleibt nämlich die SourceUnit einfach liegen, ich habe jetzt zweimal das identische Objekt in der JTable.
Java:
public Transferable createTransferable( JComponent comp ) {
// kommt weiter unten (warum, wird im Text erklärt)
}
Das erzeugt eine Wrapper-Klasse um meine eigentliche DataUnit, aber die DataUnit das Transferable-Interface implementieren zu lassen hat genauso gut funktioniert.
Java:
public boolean canImport( TransferHandler.TransferSupport support ){
return support.isDataFlavorSupported( DataUnit.flavor );
}
canImport ist soweit klar.
Jetzt wird es wieder spannend.
Java:
public boolean importData( TransferHandler.TransferSupport support ) {
// TEIL 1
JTable table = (JTable)support.getComponent();
DefaultTableModel model = (DefaultTableModel)table.getModel();
JTable.DropLocation location = (JTable.DropLocation)support.getDropLocation();
int row = location.getRow();
int col = location.getColumn();
// TEIL 2
DataUnit data = (DataUnit)support.getTransferable().getTransferData( DataUnit.flavor );
// TEIL 3
Object prevObj = model.getValueAt( row, col );
if ( (prevObj!=null) && (prevObj instanceof DataUnit) )
((DataUnit)prevObj).combine( data );
else
model.setValueAt( data, row, col );
return true;
}
Da drin passiert nun folgendes: Ich besorge mir erstmal den Ort des Drop (Teil 1), dann das Objekt, das verschoben werden soll (Teil 2) und im Teil 3 besorge ich mir das was in der Drop-Location liegt und falls da was ist, kombiniere ich das mit dem was fallengelassen wird. Ansonsten wird einfach das Objekt dort abgelegt.
Mein Problem: Obwohl ich als SourceAction ausdrücklich nur MOVE zulasse, wird die Zelle am Ausgangspunkt des D&D nicht geleert. Um das zu gewährleisten habe ich folgendes gemacht:
Java:
public Transferable createTransferable( JComponent comp ) {
...
Object obj = table.getModel().getValueAt( row, col );
table.getModel().setValueAt( null, row, col );
...
return (Transferable)obj;
}
D.h. beim Aufnehmen wird die Quell-Zelle geleert. Das sieht zwar auf den ersten Blick ok aus, aber wenn der Drag abgebrochen wird, ist das Objekt weg. Wenn der D&D außerhalb der JTable endet, dann genauso.
Deswegen meine Frage: Hat jemand ein Beispiel, wie D&D von Zellen in einer JTable richtig implementiert werden? Ich suche mir seit Tagen die Finger wund, ich finde nichts brauchbares. Oder kann mir bitte jemand unter die Arme greifen und ein paar Tips geben?
Das zweite Problem stelle ich erstmal zurück. Es geht dabei darum, daß während des Drags kein Symbol angezeigt wird und ich habe nicht herausgefunden, wie ich es anstelle, daß man eine visuelle Rückmeldung bekommt, daß gerade ein D&D in Aktion ist.