Have one JTable
on my swing screen. While loading screen, I am setting one table model which is created for this table only.
And at run time if there is any data change I am recreating the same model and again set it using objJTable.setModel(objCustTableModel)
.
Now the problem is table model which is loaded at the time of screen load, same model object get called while setting objJTable.setModel(objCustTableModel)
at run time which called getColumnClass(int col) method from CustTableModel
class. After this object call, my new model object get called. Again if I set another new
table model, by using same code objJTable.setModel(objCustTableModel2)
, model call's functions get called first from objCustTableModel
and then
objCustTableModel2
.
In short setModel()
function first call previous model object and then current model object. How can I restrict to call of previous model object?
For example
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/**
* Steps to reproduce issue.
* 1. Run this program.
* 2. There will be two rows in table. Delete all rows one by one.
* 3. Now click on Add button and see the exception.
*
* I come to know that this exception is because of table.setAutoCreateRowSorter(true); line, which is there in TestCustTableModel's constructor
* If you comment this line, then issue got resolved.
* But I want to apply sorting on columns so this line is required.
*/
public class TestCustTableModel extends JPanel{
JTable table = new JTable();
public TestCustTableModel() {
Object[][] data = new Object[2][3];
data[0][0] = "1";
data[0][1] = "User1";
data[0][2] = "Delete";
data[1][0] = "2";
data[1][1] = "User2";
data[1][2] = "Delete";
JButton addButton = new JButton("Add");
addButton.addMouseListener(new AddListener());
table.setModel(new CustModel(data));
table.addMouseListener(new TableListener());
/**#################################
* Following line throws ArrayIndexOutOfBoundsException. Please comment or Uncomment following line and see the difference.
*/
table.setAutoCreateRowSorter(true);
table.getTableHeader().setCursor(new Cursor(Cursor.HAND_CURSOR));
JScrollPane scrollPane = new JScrollPane(table);
this.add(addButton);
this.add(scrollPane);
}
class TableListener extends MouseAdapter {
public void mouseClicked(MouseEvent evnt) {
Point p = evnt.getPoint();
if(table.columnAtPoint(p) == 2) {
Object[][] data = null;
if(table.getModel().getRowCount() == 2 && table.rowAtPoint(p) == 0) {
data = new Object[1][3];
data[0][0] = "2";
data[0][1] = "User2";
data[0][2] = "Delete";
}else if(table.getModel().getRowCount() == 2 && table.rowAtPoint(p) == 1) {
data = new Object[1][3];
data[0][0] = "1";
data[0][1] = "User1";
data[0][2] = "Delete";
}else {
data = new Object[0][];
}
table.setModel(new CustModel(data));
}
}
}
class AddListener extends MouseAdapter{
@Override
public void mouseClicked(MouseEvent evnt) {
if(table.getModel().getRowCount() == 2) {
return;
}
Object[][] data = new Object[table.getModel().getRowCount() + 1][3];
for(int i = 0; i <= table.getModel().getRowCount(); i++) {
data[i][0] = i;
data[i][1] = "User" + i;
data[i][2] = "Delete";
}
table.setModel(new CustModel(data));
}
}
class CustModel extends AbstractTableModel {
private String[] columnNames = {"ID", "NAME", "DELETE"};
private Object[][] data = null;
public CustModel(Object[][] data) {
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
}
private void display() {
JFrame f = new JFrame("SwapTableModel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
TestCustTableModel obj = new TestCustTableModel();
obj.display();
}
}
at this time swing first internally called getColumnClass
function on the basis of objCustTableModel
and after that
using objCustTableModel2
object. I want to restrict call which is on the basis of objCustTableModel
.
Starting from this example, I saw no unexpected behavior with the getColumnClass()
implementation shown below.
private Model() {
final Object[] data = {this.toString()};
this.model = new DefaultTableModel(data, 1){
@Override
public Class<?> getColumnClass(int columnIndex) {
System.out.println(data[0]);
return super.getColumnClass(columnIndex);
}
};
model.addRow(data);
}
Note that JTable
may invoke getColumnClass()
anytime it determines that a cell needs rendering. If necessary, you can use EventQueue.invokeLater()
to schedule something that will "happen after all pending events are processed."
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// do something
}
});
Addenda:
If getAutoCreateRowSorter()
is true
, setModel()
tries to restore the RowSorter
created using the old model.
You can specify setAutoCreateRowSorter(true)
after you change models, as shown below, or extend your TableModel
to update the model in place, as shown here.
Use ActionListener
for JButton
instead of MouseListener
.
Use a TableCellEditor
for buttons in the table, as shown here and here.
Code:
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (table.getModel().getRowCount() == 2) {
return;
}
Object[][] data = new Object[table.getModel().getRowCount() + 1][5];
table.setRowSorter(null);
for (int i = 0; i <= table.getModel().getRowCount(); i++) {
data[i][0] = i;
data[i][6] = "User" + i;
data[i][7] = "Delete";
}
table.setModel(new CustModel(data));
table.setAutoCreateRowSorter(true);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With