How do I drag and drop a row in a JTable?
Solution 1
Check out the drag and drop section of the Java Tutorial. There are some examples on how to implement this for JTable
.
Solution 2
The following allows JTable re-ordering of a single dragged row:
table.setDragEnabled(true);
table.setDropMode(DropMode.INSERT_ROWS);
table.setTransferHandler(new TableRowTransferHandler(table));
Your TableModel should implement the following to allow for re-ordering:
public interface Reorderable {
public void reorder(int fromIndex, int toIndex);
}
This TransferHandler class handles the drag & drop, and calls reorder() on your TableModel when the gesture is completed.
/**
* Handles drag & drop row reordering
*/
public class TableRowTransferHandler extends TransferHandler {
private final DataFlavor localObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index");
private JTable table = null;
public TableRowTransferHandler(JTable table) {
this.table = table;
}
@Override
protected Transferable createTransferable(JComponent c) {
assert (c == table);
return new DataHandler(new Integer(table.getSelectedRow()), localObjectFlavor.getMimeType());
}
@Override
public boolean canImport(TransferHandler.TransferSupport info) {
boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
return b;
}
@Override
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
@Override
public boolean importData(TransferHandler.TransferSupport info) {
JTable target = (JTable) info.getComponent();
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
int index = dl.getRow();
int max = table.getModel().getRowCount();
if (index < 0 || index > max)
index = max;
target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
try {
Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
if (rowFrom != -1 && rowFrom != index) {
((Reorderable)table.getModel()).reorder(rowFrom, index);
if (index > rowFrom)
index--;
target.getSelectionModel().addSelectionInterval(index, index);
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
protected void exportDone(JComponent c, Transferable t, int act) {
if ((act == TransferHandler.MOVE) || (act == TransferHandler.NONE)) {
table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
Solution 3
I like Soley's modifications, but his code relies on an external library, and I'm not sure where he got it from, so I re-wrote it so that you don't need the TableUtil class...
@Override
public boolean importData(TransferHandler.TransferSupport info) {
JTable target = (JTable) info.getComponent();
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
int index = dl.getRow();
int max = table.getModel().getRowCount();
if (index < 0 || index > max) {
index = max;
}
target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
try {
Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
if (rowFrom != -1 && rowFrom != index) {
int[] rows = table.getSelectedRows();
int iter = 0;
for (int row : rows) {
if (index > row) {
index--;
((Reorderable) table.getModel()).reorder(row - iter, index);
}
else {
((Reorderable) table.getModel()).reorder(row, index);
}
index++;
iter++;
}
target.getSelectionModel().addSelectionInterval(index, index);
return true;
}
} catch (Exception e) {
String error = e.getMessage();
JOptionPane.showMessageDialog(null, error, "Error", JOptionPane.ERROR_MESSAGE);
}
return false;
}
MARCOS GARCES
Updated on June 23, 2020Comments
-
MARCOS GARCES almost 4 years
I'm trying to install microk8s, using Ansible.
I get the error : "No snap matching 'microk8s' available"
I'm using WSL 2 (Ubuntu 20.04), and snap version 2.44.3+20.04.
My configuration:
- name: Install microk8s snap: name: - microk8s classic: yes become: true
Does anyone know how to fix this?
-
a2f0 over 2 yearsFor anybody having trouble with this on Ubuntu 20 (without WSL), make sure to run the command to install the collection
ansible-galaxy collection install community.general
-
-
Koobz over 12 yearsI was getting exceptions upon transfer that I fixed by changing
localObjectFlavor
to:private final DataFlavor localObjectFlavor = new DataFlavor(Integer.class, "Integer Row Index");
-
Stephan over 11 years+1 But unfortunately this will not work for multiple row selection.
-
pstanton about 11 years+1 - a couple of simple modifications and this works perfectly !
-
David over 10 yearsNice example! Although I noticed a bug in exportDone. If you drag the selected value outside the component and release the curser will keep the "copy icon". I corrected this by modifying the if statement in exportDone to "act == TransferHandler.MOVE || act == TransferHandler.NONE".
-
Ignas2526 about 8 yearsGreat code. One problem I had with it, is that I kept getting
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.io.InputStream
error. Using insteadlocalObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index")
solved the error. -
ImJustACowLol over 4 yearsI find the usage of
TransferHandler
highly complicated and unnecessary... I would propose the solution that makes use of Mouse(Motion)Listeners: stackoverflow.com/questions/58043707/… -
MARCOS GARCES over 3 yearsI get: nsenter: failed to parse pid: '-a'
-
mvmn over 2 yearsWhat is TableUtil?
-
Soley over 2 yearsIt is a class that make working with rows simple. The method name is describe what we will receive from them. You can replace them by your own methods, or use Table's own methods.