【问题标题】:Pattern for updating JTable on guava events thread safe在番石榴事件线程安全上更新 JTable 的模式
【发布时间】:2012-11-02 15:33:52
【问题描述】:

初步问题

如何构建 JTable 以便在触发 Google Guava 事件时对其进行更新(并保证它是线程安全的)?

简单的方法是model.setValueAt(aValue, row, column);

两个问题:

  • 使用JTableModel的标准数据结构,不知道在哪一行。
  • 使用 JTableModel 的标准数据结构,我不能将此数据用于其他组件
  • 这不是线程安全的(我认为)

我曾想过将 JTableModel 更改为使用 ConcurrentHashMap,但这似乎不是扩展它的预期目的。我觉得这是一条通往奇怪错误的途径。

我在这一切中感到非常迷茫,如果你能提供一个我应该首先探索的指南,那将有很大帮助。

一个更明智的问题

事件不在 EVT 中。为了确保我跑了SwingUtilities.isEventDispatchThread(),结果是假的。

我现在认为我应该做什么:

@Subscribe
public void handleMessage(DataStructure newInformation) {
  // handle the information

  SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        tableModel.setValueAt(...); // update table1
        tableModel2.setValueAt(...); // update table2
    }
  });
}

如果我得到完全独立于表格的信息。我需要一种方法来了解信息与哪一行相关。
我总是可以循环遍历模型中的整个向量,但我正在寻找一种可以使用地图或数组的解决方案。

【问题讨论】:

    标签: java swing concurrency guava tablemodel


    【解决方案1】:

    对 Swing 组件的每次更改都必须在事件调度线程中完成。您可以通过调用SwingUtilities.isEventDispatchThread() 来测试您是否在事件调度线程中。如果返回 true,您可以直接修改模型。如果它返回 false,则必须在 EDT 中通过将更新包装在使用 SwingUtilities.invokeLater()(或 SwingUtilities.invokeAndWait())执行的 Runnable 中来完成更新:

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            tableModel.setValueAt(...);
        }
    });
    

    你没有说这个事件是什么,你的表模型是什么,但你当然需要能够,感谢表模型,找到哪些行和列对应于你得到的事件。通常使用 AbstractTableModel 包装 List<SomeBean>。使用列表的方法,您应该能够找到要更新的SomeBean 实例的索引。

    编辑:

    正如我所说,定义表模型的典型方法是扩展 AbstractTableModel,并基于包装的 List 实现方法。但是,只要实现了表模型契约,没有什么能阻止您使用 Map 代替或添加 List,并向模型添加其他方法。 List 将用于实现方法getValueAt()getRowCount() 等,例如,映射将允许快速找到列表中对象的索引。当然,将所有内容封装到自定义表模型中并保持两个集合同步是您的工作。

    也就是说,我会采用一个简单的解决方案,即在列表上进行迭代以找到合适的行,并且仅在您确实遇到性能问题时才尝试优化(这可能只发生在一个巨大的表中)。维护这两个集合可能比简单地在列表上循环具有更大的开销。不要过早优化:这是万恶之源。

    【讨论】:

      【解决方案2】:

      我的一般建议是使用AsyncEventBusExecutor,通过调用SwingUtilities.invokeLater(Runnable) 实现execute(Runnable)。这将导致该事件总线的所有事件处理程序仅在 EDT 上被调用。

      如果您不想在 EDT 上处理大量事件,则可以使用两个事件总线,只有一个调用 EDT 上的事件处理程序(UI 事件总线)。然后您的 UI 组件订阅 UI 事件总线。然后,您可以让您的主事件总线使用向主事件总线注册的中间对象将某些类型的事件转发到 UI,该中间对象只是将其接收到的事件发布到 UI 事件总线。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多