Java:如何在不使用TransferHandler的情况下拖动JTable行?

Java:如何在不使用TransferHandler的情况下拖动JTable行?,java,swing,user-interface,drag-and-drop,jtable,Java,Swing,User Interface,Drag And Drop,Jtable,在Java中,JTable默认情况下不提供拖动JTable行以重新排序表的功能。我在网上看到的许多答案都建议您应该使用自定义的TransferHandler实现来实现这种行为。然而,我发现这会使事情变得非常复杂,需要有一种更简单的方法来做到这一点。有人能就如何更有效地拖放表行以重新排序表给出建议吗?为了实现此行为,您可以结合使用MouseListener和MouseMotionListenerDefaultTableModel提供了将事件的点转换为事件发生所在行的功能。使用此功能,我们可以有效地

在Java中,
JTable
默认情况下不提供拖动
JTable
行以重新排序表的功能。我在网上看到的许多答案都建议您应该使用自定义的
TransferHandler
实现来实现这种行为。然而,我发现这会使事情变得非常复杂,需要有一种更简单的方法来做到这一点。有人能就如何更有效地拖放表行以重新排序表给出建议吗?

为了实现此行为,您可以结合使用
MouseListener
MouseMotionListener
DefaultTableModel
提供了将事件的
转换为事件发生所在行的功能。使用此功能,我们可以有效地拖动表行。下面的代码示例显示了实时拖动表行的基本实现。请注意,
table
tableModel
属性是特意被定义的:我们不希望
MouseHandler
保留对
table
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) {}

}
public类MouseHandler实现MouseListener、MouseMotionListener{
私有整数行=null;
私有最终WeakReference表;
私有最终WeakReference表模型;
公共鼠标手柄(JTable表、DefaultTableModel模型){
this.table=新的WeakReference(表);
this.tableModel=新的WeakReference(model);
}
@凌驾
public void mouseClicked(MouseEvent事件){}
@凌驾
公共无效鼠标按下(鼠标事件){
JTable表;
if((table=this.table.get())==null){
返回;
}
int viewRowIndex=table.rowAtPoint(event.getPoint());
行=table.convertRowIndexToModel(viewRowIndex);
}
@凌驾
公共无效MouseEvent事件(MouseEvent事件){
行=空;
}
@凌驾
public void mouseenterned(MouseEvent事件){}
@凌驾
public void mouseExited(MouseEvent事件){}
@凌驾
公共无效鼠标标记(鼠标事件){
JTable表;
DefaultTableModel表格模型;
if((table=this.table.get())==null | |(tableModel=this.tableModel.get())==null){
返回;
}
int viewRowIndex=table.rowAtPoint(event.getPoint());
int currentRow=table.convertRowIndexToModel(viewRowIndex);
if(行==null | | currentRow==row){
返回;
}
tableModel.moveRow(行,行,当前行);
行=当前行;
table.setRowSelectionInterval(viewRowIndex,viewRowIndex);
}
@凌驾
public void mouseMoved(MouseEvent事件){}
}
在我看来,这是一个比大多数使用
TransferHandler
的建议更干净、更友好的实现

更新2019年9月22日11.51 CEST 正如所建议的,原始示例在处理筛选/排序表时存在问题。该示例现已更新,以支持这些功能。在排序表中移动行时,移动的行将在下一个可见行之后插入一个索引。这意味着在基础模型中,行一次可以移动多个索引


重要提示:如果要确保移动行后表仍保持过滤/排序,请确保调用了
setSortsUpdates(true)
在您的表的排序器上。

我唯一关心的是,您没有将视图行索引转换为模型行索引——虽然我关心的是,如果您试图在当前已排序的表上执行此操作,您可以在当前已筛选的表上执行此操作,这意味着行索引将混乱。就我个人而言,我希望实现一个更抽象的实现——但由于OP没有提供任何代码,这是一个很好的工作演示。我知道我只使用Java8,但这是如何编译的?我在互联网上搜索过,找不到任何新的Java关键字“self”或方法“unwrappedPerform()”@MadProgrammer,我将对此进行研究。这只在未过滤的表上测试(因为我不使用过滤的表)。@camickr My bad,这些都是非标准API。“self”只是我从内部类中使用的一个变量,用于引用周围的父类。“unwrappedPerform”是一个我用来检查WeakReference是否为null的函数,如果不是,它所持有的弱引用属性是否为null。如果两者都不为null,则在弱引用对象上执行lambda表达式。我将把函数添加到代码示例中。@camickr因为我刚刚发现使用“self”和“unwrappedPerform”的部分与示例不相关,所以我从上面的代码中删除了它。但是,如果您仍然对函数是什么感兴趣,那么您可以看看。如前所述,我使用它在弱引用对象上执行函数:)