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

Posted

技术标签:

【中文标题】Java:如何在不使用 TransferHandler 的情况下拖动 JTable 行?【英文标题】:Java: How to drag JTable rows without usage of TransferHandler? 【发布时间】:2020-01-22 10:01:54 【问题描述】:

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

【问题讨论】:

【参考方案1】:

为了实现此行为,您可以使用MouseListenerMouseMotionListener 的组合。 DefaultTableModel 提供了可以将事件的Point 转换为发生事件的行的功能。使用此功能,我们可以有效地拖动表格行。下面的代码示例显示了实时拖动表格行的基本实现。请注意,tabletableModel 属性是故意弱化的:我们不希望 MouseHandler 保留对 tabletableModel 的强引用。

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) 


在我看来,这比大多数使用 TransferHandler 的建议更清洁、更友好。

更新 2019 年 9 月 22 日 11.51 CEST 正如@MadProgrammer 所建议的那样,原始示例在处理过滤/排序表时存在问题。该示例现在已更新为也支持这些。在排序表中移动行时,移动的行将插入到下一个可见行之后的一个索引处。这意味着在底层模型中,行可能一次移动多个索引。

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

【讨论】:

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

以上是关于Java:如何在不使用 TransferHandler 的情况下拖动 JTable 行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 java.math.BigInteger 的情况下在 Java 中处理非常大的数字

如何在不使用 Java 库中的 CyclicBarrier 的情况下制作我自己的 CyclicBarrier

如何在不使用 JButton 的情况下触发 Java 应用程序上的链接

如何在不使用临时文件的情况下从 Java 中的嵌套 zip 文件中读取数据?

如何在不使用java发送任何邮件的情况下检查域中是不是存在电子邮件ID

如何在不调整窗口大小的情况下使用 Java 在 Selenium Webdriver 中捕获屏幕截图 [重复]