如何正确触发`fireTableDataChanged`

时间:2017-03-16 13:59:26

标签: java swing jtable

我有一个合理的简单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只是因为我以某种方式错误地使用了计时器。我做错了什么?

1 个答案:

答案 0 :(得分:2)

您使用的DefaultTableModel会从Vector数组中创建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);
    }