Hi,
I have created my TableModel and want to refresh JTable once I added a new row. What should be added to the listener to \"refresh\" JTable?
publ
Use this type of casting.
((AbstractTableModel)student.getModel()).fireTableCellUpdated();
For a more general solution you can use the Row Table Model and just implement the getValueAt() and setValueAt() methods.
Here should be some code that will be firing my table after adding new row!
The model is responsible for invoking the proper fireXXX method.
Well, first of all, find more about Observer pattern (http://en.wikipedia.org/wiki/Observer_pattern).
I suggest that you create a ObservableModel class that will have a list of PropertyChangeListeners. Your StaffDAO should extend this ObservableModel. When the new staff is added (i.e. addStaff
is called) you should call ObservableModel's firePorpertyChange
or something like that. firePropertyChange
notify
ies all propertyChangeListeners. One of those listeners should be registered in your Table, and its propertyChanged
method should be implemented with refreshing of the table (hd1) had a good answer.
You've done it the hard way.
First of all, you've implemented directly from TableModel
and secondly you've failed to implement the listener requirements...
Instead, try extending from the AbstractTableModel instead, which already includes the implementations of the listener registration and notification.
You will need to provide a method that will allow you to add a row to the table model. In this method you need to use the fireTableRowsInserted method which will notify any tables using the model, that a new row has been added...
This is VERY, VERY basic example. It's only intention is to demonstrate the use of fireTableRowsInserted
. It uses a Swing Timer
to add a new row every 125 milliseconds until you kill it ;)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
public class DynamicTable {
public static void main(String[] args) {
new DynamicTable();
}
public DynamicTable() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(125, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.addRow();
}
});
timer.start();
}
});
}
public class MyTableModel extends AbstractTableModel {
private List<String[]> rows;
public MyTableModel() {
rows = new ArrayList<>(25);
}
@Override
public int getRowCount() {
return rows.size();
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
String[] row = rows.get(rowIndex);
return row[columnIndex];
}
public void addRow() {
int rowCount = getRowCount();
String[] row = new String[getColumnCount()];
for (int index = 0; index < getColumnCount(); index++) {
row[index] = rowCount + "x" + index;
}
rows.add(row);
fireTableRowsInserted(rowCount, rowCount);
}
}
}
Because your table model is backed by its own List
, it has no connection to your factory. It doesn't know when you add or remove objects from it. This means you become responsible for updating the model:
public class MyTableModel extends AbstractTableModel {
private List<Staff> staffs;
public MyTableModel(List<Staff> staffs){
this.staffs = staffs;
}
@Override
public int getRowCount() {
return staffs.size();
}
@Override
public int getColumnCount() {
return 5;
}
public void add(Staff staff) {
int size = getSize();
staffs.add(staff);
fireTableRowsInserted(size, size);
}
public void remove(Staff staff) {
if (staffs.contains(staff) {
int index = stafff.indexOf(staff);
staffs.remove(staff);
fireTableRowsDeleted(index, index);
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Staff staff = staffs.get(rowIndex);
switch (columnIndex){
case 0:
return staff.getName();
case 1:
return staff.getSurname();
case 2:
return staff.getDate();
case 3:
return staff.getPosition();
case 4:
return staff.getSalary();
}
return "";
}
}
And your actionPerformed
:
@Override
public void actionPerformed(ActionEvent e) {
Staff staff = new Staff();
staff.setName(JOptionPane.showInputDialog("Enter First Name"));
staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
staff.setDate(JOptionPane.showInputDialog("Enter Date"));
staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
try {
Factory.getInstance().getStaffDAO().addStaff(staff);
((MyTableModel)model).add(staff);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
Your class MyTableModel
implements TableModel
, but it has no event handling mechanism to connect the model to the view. Instead extend AbstractTableModel
, as shown here and here. AbstractTableModel
provides the fireTable*
methods needed for this.
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
myTableModel.fireTableDataChanged();
should be just enough to force a refresh of your table. As usual, if you have further problems, do feel free to leave a comment.