How do you setup a JTable to be able to drag a row to a different index in the table. For example if I have 5 rows and I want to drag the 4th row to the 2nd position?
5 Answers
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));
}
}
}

- 532
- 7
- 12

- 3,491
- 2
- 18
- 16
-
1I was getting exceptions upon transfer that I fixed by changing `localObjectFlavor` to: `private final DataFlavor localObjectFlavor = new DataFlavor(Integer.class, "Integer Row Index");` – Koobz Nov 27 '11 at 20:46
-
-
-
3Nice 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". – David Jan 27 '14 at 13:20
-
Great 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 instead `localObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index")` solved the error. – Ignas2526 Mar 08 '16 at 13:17
-
1I find the usage of `TransferHandler` highly complicated and unnecessary... I would propose the solution that makes use of Mouse(Motion)Listeners: https://stackoverflow.com/questions/58043707/java-how-to-drag-jtable-rows-without-usage-of-transferhandler – ImJustACowLol Sep 22 '19 at 10:16
Check out the drag and drop section of the Java Tutorial. There are some examples on how to implement this for JTable
.

- 1,150
- 3
- 11
- 17
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;
}

- 21
- 2
Just for the records and multiple row re-ordering:
use somewhere....
JTable table = t_objects;
table.setDragEnabled(true);
table.setDropMode(DropMode.INSERT_ROWS);
table.setTransferHandler(new TableRowTransferHandler(table));
This is the main class in the above answer, I modified that to match the needs for multiple row DnD. All I did was to use the first selected row, then calculate the rows above the drop place. Removed seleced items and keep them in a list of objects (row array object). then insert them back to calculated row. and finally select the removed/dragged rows to complete the process.
public class TableRowTransferHandler extends TransferHandler {
private final DataFlavor localObjectFlavor = new DataFlavor(Integer.class, "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) {
int[] rows = table.getSelectedRows();
int dist = 0;
for (int row : rows) {
if (index > row) {
dist++;
}
}
index -= dist;
//**TableUtil** is a simple class that just copy, remove and select rows.
ArrayList<Object> list = TableUtil.getSelectedList(table);
TableUtil.removeSelected(table);
ArrayList<Integer> sels = new ArrayList<Integer>();
for (Object obj : list) {
sels.add(index);
TableUtil.addRowAt(table, obj, index++);
}
TableUtil.selectMultipleRow(table, sels);
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
protected void exportDone(JComponent c, Transferable t, int act) {
if (act == TransferHandler.MOVE) {
table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}

- 1,716
- 1
- 19
- 33
-
-
It 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. – Soley Oct 10 '21 at 09:12
perhaps sth. like this:
table.addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
e.consume();
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.MOVE);
}
public void mouseMoved(MouseEvent e) {
}
});

- 7,238
- 10
- 46
- 77