JTable最大限度地减少更新时的高cpu使用率



更新:所以我发现了这个问题的原因 当我的Java窗口最小化时,我的表将呈现每一行。有人知道如何防止这种情况发生吗?

我有一个JXTable,它每秒都在不断地更新、删除和添加行数据。我们讨论的是平均每秒修改10-20行。

通常,CPU使用率在5%到10%之间。当我们每秒更新数百次时,它可以达到15%。

然而,我们注意到,当我们的Java窗口最小化时,每当任何更新通过时,我们的CPU使用率每次都会达到25%。我们设置了一个脚本,每5秒添加一行,当这一行通过时,我们看到CPU使用率达到25%。

我能想到的唯一解释是使用SwingUtilities.invokeAndWait()。我正在后台线程中修改行数据,并使用invokeAndWait来处理各种fireTableDataChanged()方法。

我使用invokeAndWait是因为我需要按顺序启动事件。例如,我删除一些行,调用fireTableRowsDeleted(),然后添加一些行,并调用fireTableRowsInserted()。

有什么想法吗?为什么只有在表更新和窗口最小化时,我的CPU使用率才会达到25%?

我使用invokeAndWait,因为我需要按顺序启动我的事件

不需要使用invokeAndWait()。您可以使用invokeLater()。事件仍将按接收顺序执行。

各种fireTableDataChanged()方法。

您不应该调用fireTableDataChanged。TableModel将调用相应的fireXXX()方法。既然只能更改几行,为什么还要重新绘制整个表呢。RepaintManager将在必要时将多个绘制请求合并为一个。

编辑:

这是我随身携带的一些代码。所有更新都是在EDT上对模型进行的,代码不会调用fireXXX(…)方法:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableThread extends JFrame
    implements ActionListener, Runnable
{
    JTable table;
    DefaultTableModel model;
    int count;
    public TableThread()
    {
        String[] columnNames = {"Date", "String", "Integer", "Decimal", "Boolean"};
        Object[][] data =
        {
            {new Date(), "A", new Integer(1), new Double(5.1), new Boolean(true)},
            {new Date(), "B", new Integer(2), new Double(6.2), new Boolean(false)},
            {new Date(), "C", new Integer(3), new Double(7.3), new Boolean(true)},
            {new Date(), "D", new Integer(4), new Double(8.4), new Boolean(false)}
        };
        model = new DefaultTableModel(data, columnNames);
        table = new JTable( model );
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.setIgnoreRepaint(false);
        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );
        JButton button = new JButton( "Start Thread to Update Table" );
        button.addActionListener( this );
        getContentPane().add(button, BorderLayout.SOUTH );
    }
    public void actionPerformed(ActionEvent e)
    {
        new Thread( this ).start();
        table.requestFocus();
    }
    public void run()
    {
        Random random = new Random();
        while (true)
        {
            final int row = random.nextInt( table.getRowCount() );
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    table.setValueAt( new Integer(count++), row, 2);
                    table.setRowSelectionInterval(row, row);
                    Object[] aRow = { new Date(), "f", row, new Double(123), new Boolean(true) };
                    model.addRow( aRow );
                }
            });
            try { Thread.sleep(500); }
            catch(Exception e) {}
        }
    }
    public static void main(String[] args)
    {
        TableThread frame = new TableThread();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible(true);
    }
}

无论帧是可见的还是最小化的,CPU都是一致的。

如果您需要更多帮助,请发布适当的SSCCE,如上面的代码,以演示问题。

JTable使用蝇量级模式只渲染可见的单元格,但主机操作系统可能会进行干扰,例如尝试为最小化的图标设置动画;个人资料。无论是什么原因,publish()都会更新为SwingWorkerdoInBackground()实现中的TableModel,如图所示。工作人员将合并更新,并以可持续的速率(约30 Hz)将其发送到process()。然后,TableModel可以以对应用程序有意义的方式推迟触发更新事件。

在JXTable中,每当模型发生变化时都会调用此方法:

protected void postprocessModelChange(TableModelEvent e) {
    if (forceRevalidate && filteredRowCountChanged) {
        resizeAndRepaint();
    }
    filteredRowCountChanged = false;
    forceRevalidate = false;
}

resizeAndRepaint()调用似乎是在最小化窗口时强制每一行重新绘制的。如下覆盖似乎可以解决问题:

@Override
protected void resizeAndRepaint()
{
    JFrame window = (JFrame)  SwingUtilities.getAncestorOfClass(JFrame.class, this);
    if(window != null && window.getState() != JFrame.ICONIFIED)
    {
        super.resizeAndRepaint();
    }
}

最新更新