Search code examples
javaswingjcomboboxlistcellrenderer

Unable to set Object instance as selected item of JComboBox with Renderer


I have a DAOImplementation class with the method definition below.

@Override
    public Registration getRegistrationInfoById(int aRegistrationId) {
        String SQL = "{CALL getRegistrationInfoById(?)}";
        Registration aRegistration = new Registration();
        try (Connection con = DBUtil.getConnection(DBType.MYSQL);
                CallableStatement cs = con.prepareCall(SQL);) {
            cs.setInt(1, aRegistrationId);
            try (ResultSet rs = cs.executeQuery();) {
                while (rs.next()) {

                    int gradeLevel = Integer.parseInt(rs.getString(RegistrationTable.GRADELEVEL));
                    aRegistration.setGradeLevel(gradeLevel);
                }
            }
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(null, e.getErrorCode() + "\n" + e.getMessage());
        }
        return aRegistration;

    }//end of method

This returns an integer value of Grade Level (1,2,3,4,5,6,7...so on...) which I've verified because I tried printing the output returned by aRegistration.getGradeLevel();

Now my problem is with my JComboBox. I have set a ListCellRenderer for my JComboBox which holds all the GradeLevel values

public class JComboBoxRenderer_GradeLevel extends JLabel implements ListCellRenderer<Object> {

    public JComboBoxRenderer_GradeLevel() {
        this.setOpaque(true);
    }

    @Override
    public Component getListCellRendererComponent(JList<? extends Object> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        if (value instanceof GradeLevel) {
            this.setText("" + ((GradeLevel) value).getGradelevel());
        } else {
            this.setText("--");
        }

        if (isSelected) {
            this.setBackground(Color.YELLOW);
            this.setForeground(list.getSelectionForeground());
        } else {
            this.setBackground(list.getBackground());
            this.setForeground(list.getForeground());
        }
        return this;
    }
}

And looks like this JComboBox as expected. (GradeLevel model is renderered to simply show an int value of gradelevel), ((GradeLevel) value).getGradelevel());returns an integer value.

enter image description here

I understand that even when JComboBox has its renderer that displays an integer value of GradeLevel by using ((GradeLevel)value).getGradeLevel(), the actual value on the JComboBox is still treated as instance of GradeLevel or object. But not a String or int.

So my problem is when I try to set the selected value to an int value, it won't change the selected value of the JComboBox. Nothing happens when I use setSelectedItem();

This is what I tried to do for the GUI.

//Grade Level
    GradeLevelDaoImpl gldi = new GradeLevelDaoImpl();
    List<GradeLevel> gradeLevels = gldi.getAllGradeLevelsInfo();
    DefaultComboBoxModel gradeLevelModel = new DefaultComboBoxModel(gradeLevels.toArray());
    jcmbGradeLevel.setModel(gradeLevelModel);
    jcmbGradeLevel.setRenderer(new JComboBoxRenderer_GradeLevel());
    jcmbGradeLevel.setSelectedIndex(-1);

GradeLevel gradeLevel = new GradeLevel();
gradeLevel.setGradelevel(registration.getGradeLevel());
jcmbGradeLevel.setSelectedItem(gradeLevel); //PROBLEM HERE, it doesn't change

JOptionPane displays this.

JOptionPane.showMessageDialog(null,"GradeLevel: "+gradeLevel);

enter image description here

JOptionPane.showMessageDialog(null,"GradeLevel: "+gradeLevel.getGradeLevel());

enter image description here

It doesn't seem to be able to compare the object I'm trying to set it to(gradeLevel) with the objects JComboBox has(gradeLevels). Notice the singular and plural.

How do I manipulate the types so that setSelectedItem() will match with what the JComboBox have?

Thanks.


Solution

  • If you want to do this by using different instances of the object, but with the same properties, then you need to override the class's equals and hashcode methods, so that the combination of properties are unique. This is very important, this is a relationship expectation that any object which is equal to another will have the same hashcode

    This is a really quick example and I used by IDE's auto generation process (because I'm lazy), but, if your Registration class has other properties which should be considered when comparing to instances of the class, you will need to modify it to support them (again, any good IDE should be able to do this)

    public class Registration {
        private int gradeLevel;
    
        public Registration(int gradeLevel) {
            this.gradeLevel = gradeLevel;
        }
    
    
        public int getGradeLevel() {
            return gradeLevel;
        }
    
        public void setGradeLevel(int gradeLevel) {
            this.gradeLevel = gradeLevel;
        }
    
        @Override
        public int hashCode() {
            int hash = 7;
            hash = 73 * hash + this.gradeLevel;
            return hash;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Registration other = (Registration) obj;
            if (this.gradeLevel != other.gradeLevel) {
                return false;
            }
            return true;
        }
    
    
    }
    

    Then using something like...

    Registration a = new Registration(1);
    Registration b = new Registration(1);
    Registration c = new Registration(2);
    
    System.out.println(a.equals(b));
    System.out.println(a.equals(c));
    System.out.println(b.equals(c));
    

    will print...

    true
    false
    false
    

    which shows us that the code is working.

    Once you get this setup, you should then be able to change the selected item by creating an instance of Registration, seeding it with the required properties and passing it to the JComboBox.

    This is very important and very common concept used a lot within Java, well worth taking the time to learn and understand