Search code examples
javaswingnetbeansjtabletablecellrenderer

Setting jCheckBox invisible in jTable


I have a jTable with two columns.First column is set as Boolean(for checkbox) and second column has String value.As I am using Netbeans,checkbox got added into all rows of first column. I tried to add it only for those rows which have value in the second column. I used the code for trying that,

private class CustomCellRenderer extends DefaultTableCellRenderer {

  /* (non-Javadoc)
   * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
   */

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

    Component rendererComp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);

             for(int i=row;i<jTable1.getRowCount();i++){

                if(jTable1.getValueAt(i, 1)==null){
                   jTable1.setValueAt(true, i, 0);
                    //checkbox.setOpaque(false);


                }
            }

        return this ;
  }

 }

If I try to set value 'true' for all other checkbox in the above for loop it's working well. How can I set it invisible for rest of the rows.

EDIT:

I am adding my code in this

   package e2;

    import java.awt.Component;
    import javax.swing.JCheckBox;
    import javax.swing.JTable;
    import javax.swing.table.TableCellRenderer;
    public class JTable_CheckBox extends javax.swing.JFrame {

        /** Creates new form JTable_CheckBox */

        JCheckBox checkbox=new JCheckBox();

        public JTable_CheckBox() {
            initComponents();
               jTable1.setValueAt("John",0,1);
               jTable1.setValueAt("James",1,1);
               jTable1.setValueAt("Janet",2,1);
               jTable1.setValueAt("Tom",3,1);

    jTable1.getColumnModel().getColumn(0).setCellRenderer(new CheckboxCellRenderer());
        }


     public static void main(String args[]) {
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new JTable_CheckBox().setVisible(true);
                }
            });
        }

        public class CheckboxCellRenderer extends JCheckBox implements TableCellRenderer {

        public CheckboxCellRenderer() {
            setOpaque(false);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                //here i am trying to set check box invisible,but here i am setting as selected

           for(int i=row;i<table.getRowCount();i++){

                    if(table.getValueAt(i, 1)==null){
                       table.setValueAt(true, i, 0);
                        //checkbox.setOpaque(false);

                    }
                }
            return this;
            }

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

    }

Solution

  • TableCellRenderer are used in tables to paint the various cells of the table reusing the same component. The table automatically sets up the proper context, component bounds and invokes the getTableCellRendererComponent for each cell of the table that needs to be painted (the first time the table is displayed all visible cells are painted and then after, upon TableModel notification, the appropriate cells are repainted).

    So in your TableCellRenderer you certainly do not need to iterate over the cells of the table trying to set values. This just does not make sense. Remember you are implementing the interface TableCellRender which has a contract you need to respect.

    From the Javadoc:

    Returns the component used for drawing the cell. This method is used to configure the renderer appropriately before drawing.

    So all you need to do is return a component representing the value parameter properly. Possibly, you can modify the component to indicate that the cell has the focus or not, and wheter it is currently selected or not. Nothing more, nothing less.

    Now, coming to your question: if you want to display a checkbox only for rows that have a value implement a TableCellRenderer returning a checkbox and modify its visibility according to the value in column 1 (second column).

    This example is working:

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.FlowLayout;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.SwingUtilities;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.TableCellRenderer;
    
    public class TestTable {
    
        public class CheckboxCellRenderer extends JPanel implements TableCellRenderer {
    
            private JCheckBox checkBox;
    
            public CheckboxCellRenderer() {
                super(new FlowLayout(FlowLayout.CENTER, 0, 0));
                setOpaque(false);
                checkBox = new JCheckBox();
                checkBox.setOpaque(false);
                checkBox.setHorizontalAlignment(JCheckBox.CENTER);
                add(checkBox);
            }
    
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                Object valueInColumn1 = table.getValueAt(row, 1);
                checkBox.setVisible(valueInColumn1 != null);
                checkBox.setSelected(value instanceof Boolean && (Boolean) value);
                return this;
            }
        }
    
        private JFrame f;
        private JTable table;
    
        private class MyObject {
            private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    
            private String value;
    
            private boolean selected;
    
            public MyObject(String value) {
                this.value = value;
            }
    
            public PropertyChangeSupport getPropertyChangeSupport() {
                return propertyChangeSupport;
            }
    
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                this.value = value;
                propertyChangeSupport.firePropertyChange("value", null, value);
            }
    
            public boolean isSelected() {
                return selected;
            }
    
            public void setSelected(boolean selected) {
                if (this.selected != selected) {
                    this.selected = selected;
                    propertyChangeSupport.firePropertyChange("selected", !selected, selected);
                }
            }
    
        }
    
        protected void initUI() {
            List<MyObject> objects = new ArrayList<TestTable.MyObject>();
            for (int i = 0; i < 200; i++) {
                MyObject object = new MyObject(i % 3 == 1 ? null : "Row " + (i + 1));
                objects.add(object);
            }
            table = new JTable(new MyTableModel(objects));
            table.setRowHeight(20);
            table.getColumnModel().getColumn(0).setCellRenderer(new CheckboxCellRenderer());
            f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(new JScrollPane(table), BorderLayout.CENTER);
            f.pack();
            f.setVisible(true);
    
        }
    
        public class MyTableModel extends AbstractTableModel implements PropertyChangeListener {
    
            private List<MyObject> objects;
    
            public MyTableModel(List<MyObject> objects) {
                super();
                this.objects = objects;
                for (MyObject object : objects) {
                    object.getPropertyChangeSupport().addPropertyChangeListener(this);
                }
            }
    
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getSource() instanceof MyObject) {
                    int index = objects.indexOf(evt.getSource());
                    fireTableRowsUpdated(index, index);
                }
            }
    
            @Override
            public int getColumnCount() {
                return 2;
            }
    
            @Override
            public int getRowCount() {
                return objects.size();
            }
    
            public MyObject getValueAt(int row) {
                return objects.get(row);
            }
    
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                switch (columnIndex) {
                case 0:
                    return getValueAt(rowIndex).isSelected();
                case 1:
                    return getValueAt(rowIndex).getValue();
                }
                return null;
            }
    
            @Override
            public void setValueAt(Object value, int rowIndex, int columnIndex) {
                if (columnIndex == 0) {
                    getValueAt(rowIndex).setSelected(Boolean.TRUE.equals(value));
                }
            }
    
            @Override
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return columnIndex == 0 && getValueAt(rowIndex).getValue() != null;
            }
    
            @Override
            public Class<?> getColumnClass(int column) {
                switch (column) {
                case 0:
                    return Boolean.class;
                case 1:
                    return String.class;
                }
                return Object.class;
            }
    
            @Override
            public String getColumnName(int column) {
                switch (column) {
                case 0:
                    return "Selected";
                case 1:
                    return "Value";
                }
                return null;
            }
    
        }
    
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
                UnsupportedLookAndFeelException {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new TestTable().initUI();
                }
            });
        }
    
    }
    

    PS: I did not take isSelected/hasFocus into account, if you want we can come to that later.