从附加了 RowSorter 的 DefaultTableModel 中删除行不会删除最后一行

发布于 2024-08-08 04:52:48 字数 2862 浏览 1 评论 0原文

我对 Java 有点陌生,尤其是表,并且在一项特定任务上遇到了一些麻烦。

我有一个 JTable,它使用扩展 DefaultTableModel 的自定义表模型,并且我已将 TableRowSorter 附加到该表。下面的示例应用程序有两个按钮——一个将行加载到表中,一个将从表中删除所有选定的行。

由于某种原因,如果您选择表中的最后一行以及任何其他行,则当您单击“删除”按钮时,它将删除除最后一行之外的所有选定行。您可以删除任何其他行组合,并且效果很好。

更重要的是,如果您首先单击列标题对行进行排序(即使行的顺序没有改变),它也会正常工作。如果我在加载后添加一行来显式对表中的行进行排序,问题就会“消失”,但我想知道为什么我所做的事情是不正确的。

要查看行为,请单击“加载”按钮填充表,选择表中的所有行,然后单击“删除”按钮。它将删除除最后一行之外的所有行。

正如对 println 的调用所示,循环的第一次迭代将所选行数减少了 2。无论表中有多少行,此行为都是一致的,但前提是您选择了表中的最后一行。

我使用的是 Java 版本 1.6.0_16。关于我做错了什么有什么想法吗?

谢谢,

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.Arrays;

public class TableTest
extends JFrame
{
  private JTable widgetTable;
  private WidgetTableModel widgetTableModel;

  public static void main(String[] args)
  {
    TableTest frame = new TableTest();
    frame.setSize(600, 400);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public TableTest()
  {
    this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    EventQueue.invokeLater(new Runnable() { public void run() { createUI(); } });
  }

  private void createUI()
  {
    this.setLayout(new BorderLayout());

    JButton loadButton = new JButton("Load");
    loadButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        loadPerformed();
      }
    });

    this.add(loadButton, BorderLayout.NORTH);

    widgetTableModel = new WidgetTableModel();
    widgetTable = new JTable(widgetTableModel);
    widgetTable.setRowSorter(new TableRowSorter<WidgetTableModel>(widgetTableModel));
    this.add(new JScrollPane(widgetTable), BorderLayout.CENTER);

    JButton removeButton = new JButton("Remove");
    removeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        removePerformed();
      }
    });

    this.add(removeButton, BorderLayout.SOUTH);
  }

  private void loadPerformed()
  {
    widgetTableModel.addRow(new Object[] {"Widget 1"});
    widgetTableModel.addRow(new Object[] {"Widget 2"});
    widgetTableModel.addRow(new Object[] {"Widget 3"});
    widgetTableModel.addRow(new Object[] {"Widget 4"});
    widgetTableModel.addRow(new Object[] {"Widget 5"});
  }

  private void removePerformed()
  {
    int selectedRow = widgetTable.getSelectedRow();

    while (selectedRow >= 0) {
      System.out.println("selectedRowCount=" + widgetTable.getSelectedRowCount());
      int modelRow = widgetTable.convertRowIndexToModel(selectedRow);
      widgetTableModel.removeRow(modelRow);
      selectedRow = widgetTable.getSelectedRow();
    }
  }
}


class WidgetTableModel
extends DefaultTableModel
{
  public WidgetTableModel()
  {
    this.addColumn("Column 1");
  }
}

I'm somewhat new to Java, and especially new to tables, and I'm having a bit of trouble with one particular task.

I have a JTable that uses a custom table model that extends DefaultTableModel, and I've attached a TableRowSorter to the table. The sample application below has two buttons--one will load rows into the table and one will remove all selected rows from the table.

For some reason, if you select the last row in the table along with any other row, when you click the "Remove" button it will remove all selected rows except the last row. You can remove any other combination of rows and it works fine.

What's more, if you first click on the column header to sort the rows (even if the order of rows doesn't change), it will work correctly. If I add a line to explicitly sort the rows in the table after loading it, the problem "goes away", but I'd like to know why what I'm doing is incorrect.

To see the behavior, click the "Load" button to populate the table, select all of the rows in the table, then click the "Remove" button. It will remove all rows except the last one.

As the call to println shows, the first iteration through the loop reduces the selected row count by two. This behavior is consistent no matter how many rows you have in the table, but only if you've selected the last row in the table.

I'm using Java version 1.6.0_16. Any ideas as to what I'm doing wrong?

Thanks,

Joe

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.Arrays;

public class TableTest
extends JFrame
{
  private JTable widgetTable;
  private WidgetTableModel widgetTableModel;

  public static void main(String[] args)
  {
    TableTest frame = new TableTest();
    frame.setSize(600, 400);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public TableTest()
  {
    this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    EventQueue.invokeLater(new Runnable() { public void run() { createUI(); } });
  }

  private void createUI()
  {
    this.setLayout(new BorderLayout());

    JButton loadButton = new JButton("Load");
    loadButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        loadPerformed();
      }
    });

    this.add(loadButton, BorderLayout.NORTH);

    widgetTableModel = new WidgetTableModel();
    widgetTable = new JTable(widgetTableModel);
    widgetTable.setRowSorter(new TableRowSorter<WidgetTableModel>(widgetTableModel));
    this.add(new JScrollPane(widgetTable), BorderLayout.CENTER);

    JButton removeButton = new JButton("Remove");
    removeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        removePerformed();
      }
    });

    this.add(removeButton, BorderLayout.SOUTH);
  }

  private void loadPerformed()
  {
    widgetTableModel.addRow(new Object[] {"Widget 1"});
    widgetTableModel.addRow(new Object[] {"Widget 2"});
    widgetTableModel.addRow(new Object[] {"Widget 3"});
    widgetTableModel.addRow(new Object[] {"Widget 4"});
    widgetTableModel.addRow(new Object[] {"Widget 5"});
  }

  private void removePerformed()
  {
    int selectedRow = widgetTable.getSelectedRow();

    while (selectedRow >= 0) {
      System.out.println("selectedRowCount=" + widgetTable.getSelectedRowCount());
      int modelRow = widgetTable.convertRowIndexToModel(selectedRow);
      widgetTableModel.removeRow(modelRow);
      selectedRow = widgetTable.getSelectedRow();
    }
  }
}


class WidgetTableModel
extends DefaultTableModel
{
  public WidgetTableModel()
  {
    this.addColumn("Column 1");
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌面超妹 2024-08-15 04:52:48

将“同时”更改为“如果”。选择所有行,然后单击按钮。由于某种原因,最后一行失去了选择。我不知道为什么。

我发现删除逻辑通常应该从最后一行到 0 完成。这样您就不必担心行索引值在删除行时发生变化。因此,您需要使用 getSelectedRows() 方法并以相反的顺序迭代数组。尽管如此,我必须承认我从未在排序表上这样做过,所以我不确定它是否会导致问题。

Change the "while" to an "if". Select all rows and then click the button. For some reason the last row loses its selection. I don't know why.

I find remove logic should generally be done from the last row down to 0. This way you don't have to worry about the row index values changes as a row is removed. So you need to use the getSelectedRows() method and iterate through the array in reverse order. Although, I must admit I've never done this on a sorted table so I'm not sure if it will cause a problem or not.

檐上三寸雪 2024-08-15 04:52:48

在 java.net 上也进行了讨论: http://www.java.net/node/698236

它是核心 DefaultRowSorter 中的 bug #6894632:在其基础上(如report) 是 getModelRowCount() 定义不太明确的语义。它已在 SwingX DefaultSortController 中修复

/** 
 * Additionally, this implementation contains a fix for core 
 * <a href=https://bugs.java.com/bugdatabase/view_bug?bug_id=6894632>Issue 6894632</a>.
 * It guarantees to only touch the underlying model during sort/filter and during 
 * processing the notification methods. This implies that the conversion and size query
 * methods are valid at all times outside the internal updates, including the critical 
 * period (in core with undefined behaviour) after the underlying model has changed and 
 * before this sorter has been notified.
 */

不幸的是,SwingLabs 论坛中的线程包含完整的分析(是: http://www.java.net/jive/thread.jspa?threadID=77343) 项目迁移后不再可用...

Discussed also on java.net: http://www.java.net/node/698236

It's bug #6894632 in core DefaultRowSorter: at its base (as explained in the report) is a not-so-well defined semantics of getModelRowCount(). It's fixed in SwingX DefaultSortController

/** 
 * Additionally, this implementation contains a fix for core 
 * <a href=https://bugs.java.com/bugdatabase/view_bug?bug_id=6894632>Issue 6894632</a>.
 * It guarantees to only touch the underlying model during sort/filter and during 
 * processing the notification methods. This implies that the conversion and size query
 * methods are valid at all times outside the internal updates, including the critical 
 * period (in core with undefined behaviour) after the underlying model has changed and 
 * before this sorter has been notified.
 */

Unfortunately, the thread in the SwingLabs forum containing the complete analysis (was: http://www.java.net/jive/thread.jspa?threadID=77343) is no longer available after the project migration ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文