我有一个合理的简单JTable,我想每秒更新一次。

为此,我发现您应该使用fireTableDataChanged(),但是,经过几次尝试,我仍然无法使其正常工作。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;

@SuppressWarnings("serial")
public class Changer extends JFrame {
    int phils = 1;
    int daves = 2;
    int bobs = 3;
    String[] cols = {"Name", "Num"};
    Object[][] data = {{"Phil", phils},
                       {"Dave", daves},
                       {"Bob", bobs}};
    DefaultTableModel dm = new DefaultTableModel(data, cols);
    JTable table = new JTable(dm);

    public Changer() {
        super("Changer");

        JPanel p = new JPanel();
        p.add(new JScrollPane(table));
        add(p);
        pack();
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        Timer t = new Timer(1000, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                phils++;
                daves++;
                bobs++;
                data = new Object[][] {{"Phil", phils},
                           {"Dave", daves},
                           {"Bob", bobs}};
                dm.fireTableDataChanged();
                repaint();
                revalidate();
                table.repaint();
                table.revalidate();

                System.out.println(phils + ", " + daves + ", " + bobs);
            }
        });

        t.start();
    }

    public static void main(String[] args) {
        new Changer();
    }
}


首先,我刚刚

Timer t = new Timer(1000, new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        phils++;
        daves++;
        bobs++;

        dm.fireTableDataChanged();
    }
});


正如文档似乎暗示的那样,如果更新值,它将起作用。

然后我尝试

Timer t = new Timer(1000, new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        phils++;
        daves++;
        bobs++;

        data = new Object[][] {{"Phil", phils},
               {"Dave", daves},
               {"Bob", bobs}};
        dm.fireTableDataChanged();
    }
});


看看是否必须物理更新变量data

最后,我添加了所有验证和重绘以查看是否会有所不同,并添加了System.out.println,以防万一我以某种方式犯错了计时器。我究竟做错了什么?

最佳答案

您使用的DefaultTableModelVector数组创建一个Object并将其用作其数据:

protected static Vector convertToVector(Object[][] anArray) {
        if (anArray == null) {
            return null;
        }
        Vector<Vector> v = new Vector<Vector>(anArray.length);
        for (Object[] o : anArray) {
            v.addElement(convertToVector(o));
        }
        return v;
    }


这意味着替换数组(甚至修改其内容)不会神奇地反映对模型的任何更改。

呼叫dm.fireTableDataChanged()之前可以做的是

替换模型数据

dm.setDataVector(data, cols);


或删除所有行并插入新行

while(dm.getRowCount()>0){
       dm.removeRow(0);
}
dm.addRow(new Object[] {"Phil", phils });
dm.addRow(new Object[] {"Dave", daves  });
dm.addRow(new Object[] {"Bob", bobs });


或搜索与名称匹配的行,然后更新该行:

updateRow(new Object[] {"Phil", phils });
updateRow(new Object[] {"Dave", daves  });
updateRow(new Object[] {"Bob", bobs });


这个updateRow方法的灵感主要来自Java JTable update row

private void updateRow( Object[] data) {

        String userName = data[0].toString();
        for (int i = 0; i < dm.getRowCount(); i++)
            if (dm.getValueAt(i, 0).equals(userName))
                for (int j = 1; j < data.length; j++)
                    dm.setValueAt(data[j], i, j);
    }

08-27 15:20