Reputation: 7734
I have a reasonable simple JTable
that I want to update every second.
To do this, I found that you are supposed to use fireTableDataChanged()
, however, after several attempts I still can't get it to work.
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();
}
}
To begin with I just had
Timer t = new Timer(1000, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
phils++;
daves++;
bobs++;
dm.fireTableDataChanged();
}
});
As the docs seem to suggest it would work if the values are updated.
Then I tried
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();
}
});
To see if I had to physically update the variable data
.
Finally I added all the validates and repaints to see if that would make a difference, and a System.out.println
just incase I had made a mistake with the timer somehow. What am I doing wrong?
Upvotes: 1
Views: 1451
Reputation: 17534
The DefaultTableModel
you are using creates a Vector
from your Object
array and uses that as its data :
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;
}
This means that replacing the array (or even modifying its content) won't magically reflect any change to the model.
What you can do before calling dm.fireTableDataChanged()
is either
Replace the data of the model
dm.setDataVector(data, cols);
Or delete all rows and insert the new ones
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 });
Or search for the row matching the name, then update the row :
updateRow(new Object[] {"Phil", phils });
updateRow(new Object[] {"Dave", daves });
updateRow(new Object[] {"Bob", bobs });
with this updateRow
method largely inspired from 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);
}
Upvotes: 2