Search code examples
javaswingjide

Working with JCheckbox with JTable in java Swing


I am using Sortable table from http://www.jidesoft.com/. Due to a requirement we need to use only this one.

We need to highlight and get count of rows when user select checkbox which is rendering as part of JTable.

My UI (My original UI is differ just adding reproducible problem).

My UI

I am expecting checkbox to be visible as a first column but it is not. I have written following lines of code to achieve this.

public void adjustTable() {
        columnModel.getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        columnModel.getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer());
    }

Above code is working, If we comment out (Checkbox is visible)

setDefaultCellRenderer(new CustomRenderer());

from constructor of StudentSortableTable.

Checkbox is visible

But when i go ahead applying highlight functionality and uncomment

setDefaultCellRenderer(new CustomRenderer());

renderer code from StudentSortableTable I can see checkbox is not visible only true/false is rendering. It is like combobox kind of. When i click true it highlight the rows.

UI with selected True

Not able to figure out how can display checkbox instead if combo box.

My source code:

public class JTableDemo extends JFrame {

    private StudentSortableTable studentSortableTable;

    private JTableDemo() {
        setBounds(300, 200, 550, 400);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                dispose();
            }
        }
        );
        initializeComponent();
    }

    void initializeComponent() {

        JPanel panel = new JPanel();

        studentSortableTable = new StudentSortableTable(getDummyData());
        studentSortableTable.adjustTable();
        studentSortableTable.setAutoCreateRowSorter(true);
        panel.add(new JScrollPane(studentSortableTable));
        add(panel);

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        JTableDemo object = new JTableDemo();
        object.setVisible(true);
    }

    private List<Student> getDummyData() {

        List<Student> students = new ArrayList<>();
        Student s1 = new Student(false, "Test User1");
        Student s2 = new Student(false, "Test User2");
        Student s3 = new Student(false, "Test User3");
        Student s4 = new Student(false, "Test User4");
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        return students;

    }
}

public class StudentModel extends DefaultTableModel {

    private static final long serialVersionUID = 1L;
    private boolean inlcludeSelect = true;

    private final List<String> columns;
    private final List<Student> studentData;

    private static final List<String> HEAD_COLUMNS = Arrays.asList("SELECTED", "NAME");

    @Override
    public Class getColumnClass(int column) {
        switch (column) {
            case 0:
                return Boolean.class;
            default:
                return super.getColumnClass(column);
        }
    }
  

    @Override
    public boolean isCellEditable(int row, int column) {
        return column == 0;
    }

    public StudentModel(List<Student> studentData) {

        columns = new ArrayList<>();
        columns.addAll(HEAD_COLUMNS);
        this.studentData = studentData;

        setDataVector(this.studentData);
    }

    private void setDataVector(List<Student> StudentArray) {

        Object[][] tableModel = new Object[StudentArray.size()][columns.size()];
        for (int rowNumber = 0; rowNumber < StudentArray.size(); rowNumber++) {
            int columNumber = 0;
            Student stdudentDataObject = StudentArray.get(rowNumber);
            if (stdudentDataObject != null) {
                tableModel[rowNumber][columNumber] = (Boolean) stdudentDataObject.isIsSelected();
                columNumber++;
                tableModel[rowNumber][columNumber] = stdudentDataObject.getName();

            }

        }

        setDataVector(tableModel, columns.toArray());
    }

    public Student getStudentData(int row) {
        return this.studentData.get(row);
    }
    
    public int getSelectedColumn() {
    return inlcludeSelect ? columns.indexOf("SELECTED") : -1;
  }

}

public final class StudentSortableTable extends SortableTable {

    private static final long serialVersionUID = 1L;

    private StudentModel studentModel;
    private final List<Student> studentData;

    public StudentSortableTable(List<Student> studentData) {
        super();

        this.studentData = studentData;
        updateModel(this.studentData);
        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setDefaultCellRenderer(new CustomRenderer());
    }

    public void updateModel(List<Student> studentData) {
        studentModel = new StudentModel(studentData);
        setModel(studentModel);
    }

    public void adjustTable() {
        columnModel.getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        columnModel.getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer());
    }

    private class CustomRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            Component c = null;
            c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (studentModel.getValueAt(row, 0) == Boolean.TRUE) {
                c.setBackground(Color.orange);
            } else {
                c.setBackground(Color.WHITE);
            }
            return c;
        }

        public Component getTableCellEditorComponent(
                JTable table,
                Object value,
                boolean isSelected,
                int row,
                int column) {
            Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
            return c;
        }
    }

}

public class Student {

    String name;
    boolean isSelected;

    public boolean isIsSelected() {
        return isSelected;
    }

    public void setIsSelected(boolean isSelected) {
        this.isSelected = isSelected;
    }

    public Student(boolean selected, String name) {
        this.isSelected = selected;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Also i am thinking how i can get count of selected out of all the rows.

EDIT After the changes

 void initializeComponent() {

        JPanel panel = new JPanel();

        studentSortableTable = new SortableTable(new StudentModel(getDummyData()));
        studentSortableTable.getColumnModel().getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        studentSortableTable.getColumnModel().getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (value.equals(Boolean.TRUE)) {
                c.setBackground(Color.orange);
            } else {
                c.setBackground(Color.WHITE);
            }
            return c;
        }
    });
       
        studentSortableTable.setAutoCreateRowSorter(true);
        panel.add(new JScrollPane(studentSortableTable));
        add(panel);

    }

Only color changes for first column

EDIT 2 :

public class StudentModel extends DefaultTableModel {

    private static final long serialVersionUID = 1L;

    private final List<String> columns;
    private final List<Student> studentData;

    private static final List<String> HEAD_COLUMNS = Arrays.asList("SELECTED", "NAME");

    @Override
    public Class getColumnClass(int column) {
        switch (column) {
            case 0:
                return Boolean.class;
            default:
                return super.getColumnClass(column);
        }
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        return column == 0;
    }

    public StudentModel(List<Student> studentData) {
        columns = new ArrayList<>();
        columns.addAll(HEAD_COLUMNS);
        this.studentData = studentData;

        setDataVector(this.studentData);
    }

    private void setDataVector(List<Student> StudentArray) {
        Object[][] tableModel = new Object[StudentArray.size()][columns.size()];
        for (int rowNumber = 0; rowNumber < StudentArray.size(); rowNumber++) {
            int columNumber = 0;
           Student stdudentDataObject = StudentArray.get(rowNumber);
            if (stdudentDataObject != null) {
                tableModel[rowNumber][columNumber] = (Boolean) stdudentDataObject.isIsSelected();
                columNumber++;
                tableModel[rowNumber][columNumber] = stdudentDataObject.getName();
            }
        }
        setDataVector(tableModel, columns.toArray());
    }

    public Student getStudentData(int row) {
        return this.studentData.get(row);
    }

}

public class TableDemo extends JFrame {

    private JTable studentSortableTable;

    private TableDemo() {
        setBounds(300, 200, 550, 400);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                dispose();
            }
        }
        );
        initializeComponent();
    }

    void initializeComponent() {

        JPanel panel = new JPanel();

        studentSortableTable = new JTable(new StudentModel(getDummyData()));
        studentSortableTable.getColumnModel().getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        studentSortableTable.getColumnModel().getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                    boolean hasFocus, int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                if (value.equals(Boolean.TRUE)) {
                    c.setBackground(Color.orange);
                } else {
                    c.setBackground(Color.WHITE);
                }
                return c;
            }
        });
        studentSortableTable.setAutoCreateRowSorter(true);
        panel.add(new JScrollPane(studentSortableTable));
        add(panel);

    }

    public static void main(String[] args) {
        TableDemo object = new TableDemo();
        object.setVisible(true);
    }

    private List<Student> getDummyData() {

        List<Student> students = new ArrayList<>();
        Student s1 = new Student(false, "Test User1");
        Student s2 = new Student(false, "Test User2");
        Student s3 = new Student(false, "Test User3");
        Student s4 = new Student(false, "Test User4");
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        return students;

    }

}

Solution

  • void initializeComponent() {
        JPanel panel = new JPanel();
        studentSortableTable = new SortableTable(new StudentModel(getDummyData()));
        studentSortableTable.getColumnModel().getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        // studentSortableTable.getColumnModel().getColumn(0).setCellRenderer(new
        // BooleanCheckBoxCellRenderer());
        studentSortableTable.getColumnModel().getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                    boolean hasFocus, int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                if (value.equals(Boolean.TRUE)) {
                    c.setBackground(Color.orange);
                } else {
                    c.setBackground(Color.WHITE);
                }
                return c;
            }
        });
        studentSortableTable.setAutoCreateRowSorter(true);
        panel.add(new JScrollPane(studentSortableTable));
        add(panel);
    }
    

    will give you the correct rendering behaviour. Colour tweaking can be done in the normal way I wouldn't mix up the concept of being "selected" in the Student class - that's a gui thing and probably doesn't belong in a data model. I haven't looked at their Javadoc but it's not inconceivable that the above kind of styling could be possible via the api directly as opposed to overriding methods Rendering