mrt181
mrt181

Reputation: 5316

Why is itemStateChanged only called once when I iterate through a columns TableCellEditor in each row?

I am using a custom CellEditor in a column

UPDATE: added a SSCCE

public class TestJFrame extends javax.swing.JFrame {

    public TestJFrame() {
        initComponents();
        jTable1.getTableHeader().addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(final MouseEvent e) {
                final JTableHeader tableHeader = (JTableHeader) e.getSource();
                final JTable table = tableHeader.getTable();
                final int column = tableHeader.columnAtPoint(e.getPoint());
                if (column == 1) {
                    TableCellEditor editor = table.getColumnModel()
                                                  .getColumn(column)
                                                  .getCellEditor();
                    for (int row = 0; row < table.getModel().getRowCount(); row++) {
                        if (table.getModel().isCellEditable(row, column)) {
                            editor.getTableCellEditorComponent(table, (e.getButton() == MouseEvent.BUTTON1),
                                                               false,
                                                               row,
                                                               column);
                            tableHeader.getTable().setValueAt((e.getButton() == MouseEvent.BUTTON1),
                                                              row,
                                                              column);
                        }
                    }
                }
            }
        });
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "name", "click me"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Boolean.class
            };
            boolean[] canEdit = new boolean [] {
                false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane1.setViewportView(jTable1);
        if (jTable1.getColumnModel().getColumnCount() > 0) {
            jTable1.getColumnModel().getColumn(0).setResizable(false);
            jTable1.getColumnModel().getColumn(0).setPreferredWidth(100);
            jTable1.getColumnModel().getColumn(1).setCellEditor(new SwitchCellEditor(new EnableCheckbox(jTable1), jTable1));
        }

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 91, Short.MAX_VALUE)
                .addGap(0, 0, 0))
        );

        pack();
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TestJFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration                   

    private static class EnableCheckbox extends JCheckBox {

        public EnableCheckbox(final JTable table) {
            addItemListener(new EnableCheckboxItemListenerImpl(table));
    }

        private final class EnableCheckboxItemListenerImpl implements ItemListener {

            private final JTable _table;

            public EnableCheckboxItemListenerImpl(final JTable table) {
                _table = table;

            }

            @Override
            public void itemStateChanged(ItemEvent e) {
                final JCheckBox checkBox = (JCheckBox) e.getSource();
                final int selectedRow = _table.rowAtPoint(checkBox.getLocation());
                final int selectedColumn = _table.columnAtPoint(checkBox.getLocation());

                // doStuff                
            }
        }
    }

    private class SwitchCellEditor extends DefaultCellEditor {

        private final JTable _table;
        private final JCheckBox _checkBox;

        public SwitchCellEditor(final JCheckBox checkBox, final JTable table) {
            super(checkBox);
            _checkBox = checkBox;
            _table = table;
        }

        @Override
        public final Component getTableCellEditorComponent(
                final JTable table,
                final Object value,
                final boolean isSelected,
                final int row,
                final int column) {

            Rectangle r = _table.getCellRect(row, column, false);

            if (_checkBox != null) {
                _checkBox.setLocation(new Point(r.x, r.y + r.height));
                return super.getTableCellEditorComponent(table, value, isSelected, row, column);
            }

            return super.getTableCellEditorComponent(table, value, isSelected, row, column);
        }
    }
}

The itemStateChanged method is only called on the first iteration step, but not on the following iteration steps.

Why is it behaving like that and how can I make it call itemStateChanged on each iteration step?

Upvotes: 1

Views: 67

Answers (1)

trashgod
trashgod

Reputation: 205825

Your implementation … does not call itemStateChanged for each editor in each row.

Exactly. JTable uses the flyweight pattern for editors, updating the TableModel only after the editor concludes. If you want to see the editor's state change, you can either

  • Use the approach in the example cited here, in which the editor listens to the JCheckBox used by the corresponding renderer.

  • Add a CellEditorListener, mentioned here.

Upvotes: 1

Related Questions