-2

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;

    }

}
  • To get the count: loop through you list of Students and count how many are selected. The list is your data model. – Just another Java programmer May 02 '23 at 14:26
  • The issue is with your BooleanCheckBoxRenderer. – camickr May 02 '23 at 14:26
  • Also note that you lose custom renderers/editors whenever you change the model. So you would need to invoke the adjustTable() method whenever you use setModel(...). – camickr May 02 '23 at 14:36
  • Personally, unless you *really* know what you're doing, I wouldn't extend `SortableTable` but simply *use* it – g00se May 02 '23 at 14:54
  • @camickr, can you please elaborate what is wrong with this? Thanks – user21528347 May 02 '23 at 17:43
  • 1) I gave you advice in your previous question which you have deleted. You still don't understand the concept of model/view. The table show the data in a sorted view. The model does NOT sort the data. Therefore when the data is sorted, the index used to access the data in the model is not the same as the index of the data in the view. I gave you the method you need to convert the index. 2) I don't know what is wrong with the renderer since the renderer code is not posted. – camickr May 02 '23 at 18:35
  • Maybe this will help: https://stackoverflow.com/a/56877885/131872. If you need more help, post a proper [mre] to demonstrate the problem. That is in order to test the renderer just use a standard JTable without all you custom classes. Once that works, then you use the knowledge to fix your code. – camickr May 02 '23 at 18:37
  • *Only color changes for thefirst column* - that is because you need to apply the highlighting logic to ALL renderers used by the table. I would also check out [Table Row Rendering](https://tips4java.wordpress.com/2010/01/24/table-row-rendering/) for an approach to highlight rows. With this approach there is no need for the custom renderers. – camickr May 02 '23 at 18:53
  • Also, your StudentTableModel should NOT extend DefaultTableModel. You end up storing the data in two places, once in the List objects of the model and the second in the DefaultTableModel. See: [Row Table Model](https://tips4java.wordpress.com/2008/11/21/row-table-model/) for an example of how to create your model by extending AbstractTableModel. – camickr May 02 '23 at 21:11
  • (1-) *can you please elaborate what is wrong* - I did. Apparently you expect people to actually write the code for you since you have only responded to the code below. You have been given suggestions on how to improve your code and better understand how a JTable works. You have been given an example on how to create an [mre]. – camickr May 03 '23 at 13:35
  • @camickr, no it is not case. Somewhere I am trying the things but no luck. The answer solution g00s shared applicable for column 0 and now I am thinking how I can apply for other column which I am looking – user21528347 May 03 '23 at 18:35
  • *... and now I am thinking...* There's not much thinking to do as I told you [here](https://stackoverflow.com/questions/76155776/working-with-jcheckbox-with-jtable-in-java-swing?noredirect=1#comment134306190_76156312) what to do, though it should have said `DefaultTableCellRenderer` – g00se May 03 '23 at 18:50
  • @g00se thanks for reply. I am new baby in this and trying my best – user21528347 May 03 '23 at 18:59
  • *now I am thinking how I can apply for other column* - and I have already given you TWO approaches. One repeated the suggestion by g00se and the second was a different approach which included a link to a working example. What more do you expect? – camickr May 03 '23 at 19:00
  • @camickr, able to solve it with the help of https://tips4java.wordpress.com/2010/01/24/table-row-rendering/. thanks for the timing. – user21528347 May 04 '23 at 04:51
  • **I am using Sortable table from http://www.jidesoft.com/. Due to a requirement we need to use only this one.** <-- I refer you to your opening comment (a comment that I took at face value). Suddenly showing a solution that concerns `JTable` is not congruent with that – g00se May 04 '23 at 10:33

1 Answers1

1
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

g00se
  • 3,207
  • 2
  • 5
  • 9
  • Thanks for adding. can you please more code/clarification . Because in my case I tried but it is not working. – user21528347 May 02 '23 at 15:29
  • *Because in my case I tried but it is not working.* That doesn't tell us anything – g00se May 02 '23 at 15:36
  • sorry for this. I did the same changes what you suggested. with the suggested change i can see checkbox is coming. But to colour tweaking behvior i have added CustomRenderer which i pasted in original post but facing same issue like instead of checkbox again it converted in Jcombox box. – user21528347 May 02 '23 at 15:40
  • Just override the renderer inline in the code I gave you. It works fine but you want `if (value.equals(Boolean.TRUE))` - IOW don't refer to the model – g00se May 02 '23 at 15:55
  • sorry if you code snippet can you paste for me. – user21528347 May 02 '23 at 16:17
  • modified the code as you suggested but when i click check box it only change the background color of first column only. Added screen in above question. – user21528347 May 02 '23 at 17:01
  • I can't keep doing tweaks but if you want the neighboring column to be orange as well, then set a cell renderer for that column too. Anonymous subclass of `DefaultCellRenderer`. It will test the value of column 0 in its own row – g00se May 02 '23 at 18:00
  • same I tried we can see our code but it convert checkbox to text. It seems in DefaultCellRender we need to some changes.Thanks you. – user21528347 May 02 '23 at 18:06
  • Above is an image of the result of the extra code as I just described to you – g00se May 02 '23 at 20:40
  • i think something i am doing wrong which i am not able figure out. I have pasted my modified code can you please look around it ? in my case only first column color get changed. – user21528347 May 03 '23 at 05:18
  • 1
    You *are* doing something wrong. You are ignoring my recommendations (unless I read the wrong code). I've already given you the working code bar a few lines, which I've described in detail how to write. – g00se May 03 '23 at 08:00
  • _i am not able figure out_ this is the solution complete with working code - use it, modify it for your exact context. When it starts to misbehave, compare the change with the last working example. Rinse and repeat :) Don't forget to study a tutorial about how to use tables/renderers to understand the effects of your changes. – kleopatra May 03 '23 at 08:17
  • @g00se , i am able to solve it. with the help of https://tips4java.wordpress.com/2010/01/24/table-row-rendering/. Thanks for your timing. – user21528347 May 04 '23 at 04:50