【问题标题】:JTable - UI freezes upon many insertionsJTable - UI 在许多插入时冻结
【发布时间】:2013-01-09 10:09:57
【问题描述】:

我有一个 GUI 应用程序,它有几个选项卡,每个选项卡都有一个 JTable。我的 UI 类在以下代码中处理来自控制器的事件,该代码在 EDT 上运行:

private void processAnalysisResult(AnalysisResult generatedValue) {
    LimitType limit = generatedValue.getMetric().getLimit();
    String limitName = limit.getName();
    int index = tabs.indexOfTab(limitName);
    Component component = tabs.getComponentAt(index);
    JScrollPane scrollPane = (JScrollPane) component;
    JTable table = (JTable) scrollPane.getViewport().getView();
    AnalysisResultTableModel model = (AnalysisResultTableModel) table.getModel();
    model.addRow(generatedValue);
    }
}

每秒有几千个新生成的结果,我将其降低到大约 10k。即使具有相对较低的值,应用程序也会冻结大约 10-20 秒来处理来自 Jtable 的 UI 更新。 addRow 方法在插入每一行时调用 fireTableRowsInserted mewthod,但这会那么慢吗?

编辑:这是处理事件的代码(从后台处理线程异步调用):

  controller.addAnalysisGenerationListener(new GeneratedValueListener<AnalysisResult>() {
        @Override
        public void valueGenerated(final GeneratedValueEvent<AnalysisResult> event) {
            processEDT(new Runnable() {
                @Override
                public void run() {
                    processAnalysisResult(event.getGeneratedValue());
                }
            });
        }
    });


private void processEDT(Runnable runnable) {
    if (EventQueue.isDispatchThread()) {
        runnable.run();
    } else {
        SwingUtilities.invokeLater(runnable);
    }
}

【问题讨论】:

    标签: java swing concurrency jtable event-dispatch-thread


    【解决方案1】:

    是的,它可能会那么慢。 10k不是一个低数字。正如您已经注意到 addRow() 调用 fireTableRowsInserted() 反过来通知视图发生了更改并刷新视图(但在这种情况下,用户看不到它,因为 EDT 正忙于处理下一个结果) . 一种解决方案是在后台线程上执行processAnalysisResult(),并通过将最后一行 (model.addRow(generatedValue);) 传递给SwingUtilities.invokeLater() 来更新 EDT 上的模型。也许它不会更快,但至少 GUI 不会冻结 20 秒。 当然,您也可以使用专用于此类任务的SwingWorker。 此外,您可以尝试批量更新模型(例如,在 EDT 上一次将每 100 个结果添加到模型中),这样可以最大限度地减少屏幕闪烁。

    【讨论】:

    • Sorry,忘了说,启动整个分析的代码,又调用了上面的方法,已经在后台线程的后面运行了
    • 如果 GUI 冻结,则意味着 processAnalysisResult() 在 EDT 的单个事件处理中循环调用。应更改调用代码,以便在发送到 EDT 的单独事件上,每个 generatedValue 调用一次 processAnalysisResult()。这样 EDT 将有机会处理其他未决的 GUI 事件(即刷新视图)。另一个好主意是通过调用fireTableRowsInserted() 一次的addRows() 方法扩展模型,正如@StanislavL 提到的那样。
    • 嗯,发生的事情正是您所描述的 - 后台线程正在生成一个事件,随后在 EDT 上一次处理一个事件。但 GUI 仍然挂起......
    • 你能展示将事件传递给 EDT 并调用 processAnalysisResult() 的代码吗?
    【解决方案2】:

    猜AnalysisResultTableModel是DefaultTableModel的instanceof?

    尝试批量添加 addRows() 方法,而不是一一添加。 addRow() 调用方法

    public void insertRow(int row, Vector rowData) {
        dataVector.insertElementAt(rowData, row);
        justifyRows(row, row+1);
        fireTableRowsInserted(row, row);
    }
    

    尝试实现类似的东西

    public void insertRows(int row, Vector<Vector> rowsData) {
        for () {
            dataVector.insertElementAt(rowData, row);
            justifyRows(row, row+1);
        }
    
        fireTableRowsInserted(row, row+rowsData.size());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-27
      • 2011-11-22
      • 1970-01-01
      • 1970-01-01
      • 2021-04-20
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      相关资源
      最近更新 更多