问题的简要描述。

假设我们有 JTable 和用户以某种方式与之交互。这个表的TableModel 是不断变化的。如何确保当用户试图通过引用一些常量列和当前选定的行(通过他从 JTable 获得的 rowIndex)从表中获取一些信息时,他不会陷入更改 TableModel 并且他从 JTable 获得的 rowIndex 的情况不再对应于 TableModel 中的相同值。

以下是更详细地解释问题的初始问题:

考虑以下情况:

  • 有一个 JTable,它显示了一些系统中当前正在运行的请求的用户信息
  • 当新的请求进入系统时,新的行被添加到表中
  • 用户可以通过右键单击一行(表中使用单行选择模型)并从菜单中选择选项(如:中止、推迟、重试等)来与表进行交互。
  • 有单独的类实现 ActionListener 接口(interface)(监听表)并处理所有用户交互
  • 当用户对表执行某些操作时,此类检查当前选定的行并为用户的操作分配一些值(基本上它获取选定行的索引,然后调用 tableModel.getValueAt(indexOfSelectedRow, someValueDataColumnIndex))

  • 现在考虑系统处于压力测试中并且请求不断高频率提交的场景。在我的情况下,这会导致一个错误,当有时处理用户操作的类从表模型中获取错误信息时(在一行上调用了操作,但对另一行执行了操作,通常是下一行)。我相信发生这种情况是因为在处理类表模型的某些初始化过程中,由于接受了新请求,因此更改了类表模型。

    问题是,如何解决这个问题。我正在考虑两种方法:
  • 在我的用户操作的处理类中使用类似 invokeAndWait() 的东西进行初始化(不喜欢这个想法,因为它会导致其他不可预测的错误)
  • 创建单独的监听器类,该类将监听表中的用户选择,并在从 TableModel 单独选择选定行后立即存储来自所选行的数据。这样操作处理类将不会从正在更改的表模型中获取数据,而是从所选行中获取数据,这在所描述的场景中是不变的。 (不确定这个想法是否可行)

  • 请评论我的想法,并提出你的建议。

    我很抱歉这里没有任何代码,但原始代码会占用太多空间,模型示例在这里不容易完成。

    最佳答案

    我不认为在表中插入行会更改选择,因此只要您在 EDT 上更新 TableModel,当用户显示弹出窗口并从弹出窗口中选择和操作时,所选行仍然相同。

    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    
    import javax.swing.*;
    import javax.swing.table.DefaultTableModel;
    
    public class TestJTableInsert {
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    final DefaultTableModel model = new DefaultTableModel(0, 1);
                    new Timer(500, new ActionListener() {
                        private final Random random = new Random();
                        private int data = 1;
    
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            model.insertRow(random.nextInt(model.getRowCount() + 1),
                                    new Object[] { data++ });
                        }
                    }).start();
    
                    final JTable table = new JTable(model);
                    JPopupMenu popup = new JPopupMenu();
                    popup.add(new AbstractAction("Which row is this?") {
    
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            JOptionPane.showMessageDialog(table,
                                    "This is row " + table.getValueAt(table.getSelectedRow(), 0));
                        }
                    });
                    table.setComponentPopupMenu(popup);
                    JFrame frame = new JFrame("Test");
                    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    frame.getContentPane().add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }
    

    10-08 17:35