Listeneing for changes in JCheckBox in a JTable
Asked Answered
S

4

8

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.

Soma answered 2/3, 2014 at 11:49 Comment(0)
S
2

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.

Soma answered 2/3, 2014 at 16:10 Comment(1)
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 interactionNeille
M
13

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);
        }
    }
}

enter image description here

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();
            }
        });
    }
}
Meadors answered 2/3, 2014 at 13:43 Comment(6)
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.Soma
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.Meadors
+1 but please to read, result should be listening into setValueAt for production codeMonger
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.Soma
@Soma 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"Meadors
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.Soma
S
2

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.

Soma answered 2/3, 2014 at 16:10 Comment(1)
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 interactionNeille
V
1

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.

Vaginal answered 2/3, 2014 at 20:54 Comment(0)
C
0

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);
        }      
    }   
Chinachinaberry answered 7/8, 2020 at 13:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.