Java: How to drag JTable rows without usage of TransferHandler?

旧城冷巷雨未停 提交于 2019-12-11 17:00:58

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!