How do I listen for changes in a JTable column that has a JCheckBox in it? I want to know when the user selects/deselects the check box. The class for the column is set as boolean so it is automatically rendered as a JCheckBox.
4 Answers
I think what you want is to listen for data changes in the TableModel
by using a TableModelListener
. It's also possible to use a custom editor, but I think the TableModelListener
is the simplest way to go. Your overriden tableChanged
method could look something like this
@Override
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
if (column == BOOLEAN_COLUMN) {
TableModel model = (TableModel) e.getSource();
String columnName = model.getColumnName(column);
Boolean checked = (Boolean) model.getValueAt(row, column);
if (checked) {
System.out.println(columnName + ": " + true);
} else {
System.out.println(columnName + ": " + false);
}
}
}
Here's a complete running example
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class TestTableModelListener {
private static final int BOOLEAN_COLUMN = 2;
public TestTableModelListener() {
JTable table = createTable();
table.getModel().addTableModelListener(new CheckBoxModelListener());
JFrame frame = new JFrame();
frame.add(new JScrollPane(table));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JTable createTable() {
String[] cols = {"COL", "COL", "COL"};
Object[][] data = {{"Hello", "Hello", false}, {"Hello", "Hello", false}};
DefaultTableModel model = new DefaultTableModel(data, cols) {
@Override
public Class getColumnClass(int column) {
return column == BOOLEAN_COLUMN ? Boolean.class : String.class;
}
};
JTable table = new JTable(model);
return table;
}
public class CheckBoxModelListener implements TableModelListener {
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
if (column == BOOLEAN_COLUMN) {
TableModel model = (TableModel) e.getSource();
String columnName = model.getColumnName(column);
Boolean checked = (Boolean) model.getValueAt(row, column);
if (checked) {
System.out.println(columnName + ": " + true);
} else {
System.out.println(columnName + ": " + false);
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestTableModelListener();
}
});
}
}

- 205,037
- 37
- 486
- 720
-
The problem with the tableChanged method is that it does not tell me when the value of the boolean actually changed, an this is what I need to capture. – user3245747 Mar 02 '14 at 13:49
-
What do you mean it doesn't tell you when it's changed? I'm not sure I'm following. It seems that this is exactly what the listener does, tell you when the value changes. – Paul Samsotha Mar 02 '14 at 13:56
-
2+1 [but please to read](http://stackoverflow.com/questions/8099098/why-never-change-the-notifier-in-receiving-a-change-event), result should be listening into setValueAt for production code – mKorbel Mar 02 '14 at 15:01
-
peeskillet: try moving the cursor into and out of the cell without changing anything. You will see that there will still be output. This is because table changed does not just capture change in data, it captures any movement in the cells. – user3245747 Mar 02 '14 at 15:39
-
@user3245747 I'm not sure the behavior you're talking about, I don't get it. Also your statement is incorrect. As stated in the tutorial _"A table model can have a set of listeners that are notified whenever the table data changes"_ – Paul Samsotha Mar 02 '14 at 15:48
-
peeskillet: Yes, the tableChanged method can be used to notify the listeners when data is changed, but it is also called even if the data is not changed. if you move into the cell of the column with the JCheckBox and move out without changing the value of the cell the tableChanged method is still called and the expression if (checked) will still be evaluated even though it has not been changed. This is why I ended up using setvalueAt as mKorbel suggested. I will post it below when I can. – user3245747 Mar 02 '14 at 16:08
Thanks to the comment by mKorbel, I re-wrote the setValueAt method for the table model as such:
public void setValueAt(Object value, int row, int col) {
super.setValueAt(value, row, col);
if (col == 4) {
if ((Boolean) this.getValueAt(row, col) == true) {
//code goes here
}
else if ((Boolean) this.getValueAt(row, col) == false) {
//code goes here
}
}
}
Now the code is only executed when the value in the cell actually changes, which is what I want.

- 805
- 2
- 17
- 30
-
Although this might work for you, it does not answer the question whether user selects or deselects the checkbox. The method setValueAt could be also called programmatically without actual user interaction – brox Feb 16 '21 at 20:49
Now the code is only executed when the value in the cell actually changes, which is what I want.
Check out the Table Cell Listener which was specifically designed for this situation.

- 321,443
- 19
- 166
- 288
Other way, it is create an MouseClicked event in the JTable, the event is fired when you click in somewhere in the jtable. Inside the event, we save the number of row and number of column. Then we imagine that we have two checkbox in column 4 and column 5 of Jtable. For example, if we pressed row 2 and column 4, we mark the checkbox in the JTable and we save the boolean value of the checbox in a dataBase using an update sql sentence.
private void RegistroFacturaTableMouseClicked(java.awt.event.MouseEvent evt) {
int filaSeleccionada = RegistroFacturaTable.rowAtPoint(evt.getPoint());
int columnaSeleccionada = RegistroFacturaTable.columnAtPoint(evt.getPoint());
if(evt.getClickCount() == 2){
int idRegistroFactura = (int) RegistroFacturaTable.getValueAt(filaSeleccionada, 0);
setVisible(false);
new VerCobros(this, idRegistroFactura, contrato);
} else if (columnaSeleccionada == 4 ){
int idRegistroFactura = (int) RegistroFacturaTable.getValueAt(filaSeleccionada, 0);
boolean agua = (boolean) RegistroFacturaTable.getValueAt(filaSeleccionada, 4);
DataBase.updateRegistroFacturaSetAguaWhereIdRegistroFactura(agua, idRegistroFactura);
} else if ( columnaSeleccionada == 5 ){
int idRegistroFactura = (int) RegistroFacturaTable.getValueAt(filaSeleccionada, 0);
boolean luz = (boolean) RegistroFacturaTable.getValueAt(filaSeleccionada, 5);
DataBase.updateRegistroFacturaSetLuzWhereIdRegistroFactura(luz, idRegistroFactura);
}
}

- 151
- 1
- 4