问题
In Java, JTable by default does not offer the functionality to drag JTable rows for reordering the table. Many of the answers I see online, suggest that you should use a custom TransferHandler implementation to achieve this behaviour. However, I find that that highly overcomplicates things and there needs to be an easier way to do so. Can anyone give suggestions on how to more efficiently drag & drop table rows for reordering the table?
回答1:
In order to achieve this behavior, you can use a combination of a MouseListener and a MouseMotionListener. DefaultTableModel provides functionality with which you can translate the Point of an event to the row in which the event occured. Using this functionality, we can effectively drag table rows around. The code sample below shows a basic implementation with which table rows are dragged in real-time. Please note that the table and tableModel properties are weakified on purpose: We do not want the MouseHandler to keep a strong reference to either the table or the tableModel.
public class MouseHandler implements MouseListener, MouseMotionListener {
private Integer row = null;
private final WeakReference<JTable> table;
private final WeakReference<DefaultTableModel> tableModel;
public MouseHandler(JTable table, DefaultTableModel model) {
this.table = new WeakReference<>(table);
this.tableModel = new WeakReference<>(model);
}
@Override
public void mouseClicked(MouseEvent event) {}
@Override
public void mousePressed(MouseEvent event) {
JTable table;
if((table = this.table.get()) == null) {
return;
}
int viewRowIndex = table.rowAtPoint(event.getPoint());
row = table.convertRowIndexToModel(viewRowIndex);
}
@Override
public void mouseReleased(MouseEvent event) {
row = null;
}
@Override
public void mouseEntered(MouseEvent event) {}
@Override
public void mouseExited(MouseEvent event) {}
@Override
public void mouseDragged(MouseEvent event) {
JTable table;
DefaultTableModel tableModel;
if((table = this.table.get()) == null || (tableModel = this.tableModel.get()) == null) {
return;
}
int viewRowIndex = table.rowAtPoint(event.getPoint());
int currentRow = table.convertRowIndexToModel(viewRowIndex);
if(row == null || currentRow == row) {
return;
}
tableModel.moveRow(row, row, currentRow);
row = currentRow;
table.setRowSelectionInterval(viewRowIndex, viewRowIndex);
}
@Override
public void mouseMoved(MouseEvent event) {}
}
This in my eyes is a much cleaner and more friendly implementation than most of the suggestions out there that use TransferHandler.
Update 22th september 2019 11.51 CEST As suggested by @MadProgrammer, the original example has issues when dealing with filtered/sorted tables. The example has now been updated to also support those. When moving rows in a sorted table, the moved row will be inserted one index after the next visible row. This means that in the underlying model, the row may be moved more than one index at a time.
Important: When you want to ensure that your table remains filtered/sorted after moving the row, ensure that you called setSortsOnUpdates(true) on your table's sorter.
来源:https://stackoverflow.com/questions/58043707/java-how-to-drag-jtable-rows-without-usage-of-transferhandler