Search code examples
javaswingeventsnumbersjcombobox

What is difference between event.getItem() and comboBox.getSelectedItem() while casting the object


I have a panel with a combobox. I am adding id numbers to the combobox. But before adding any id, I am adding a empty String to know that no id is selected.

JComboBox jcPatientIds;
JPanel patientPanel;

public void updateIdsInComboBoxes(ArrayList<Integer> items)
{
    getJcPatientIds().addItem("");
    if (items.size() > 0)
    {
        for (Integer item : items)
        {
            getJcPatientIds().addItem(item);
        }
    }
    getPatientPanel().add(getJcPatientIds());
}

public JComboBox getJcPatientIds()
{
    if(jcPatientIds == null)
    {
    jcPatientIds = new JComboBox();
    jcPatientIds.setBounds(250, 20, 100, 20);
    }
    return jcPatientIds;
}

public JPanel getPatientPanel()
{
    if(patientPanel == null)
    {
        patientPanel = new JPanel();
    }
    return patientPanel;
}

Now, I have listener class as like this. And it works fine without giving any error

@Override
public void itemStateChanged(ItemEvent e)
{
    /*The event triggers for both deselected and selected item
    Here only the   selected event will be triggered with value 1
                    deselected event has a value 2*/
    if (e.getStateChange() == 1)
    {
        if (e.getItem().equals(""))
        {
            // Some stuff
        }
        else
        {
        System.out.println((int) e.getItem());
            // Some other stuff
        }
    }
}

But, If I use getSelectedItem on Combobox. I am getting ClassCastException. What is the problem here

@Override
public void itemStateChanged(ItemEvent e)
{
        if (getJcPatientIds.getSelectedItem().equals(""))
        {
            // Some stuff
        }
        else
        {
        System.out.println((int) getJcPatientIds.getSelectedItem()); // Here I am getting ClassCastException
            // Some other stuff
        }
    }
}

Error

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at hospitalApp.common.PatientController.itemStateChanged(PatientController.java:71)
at javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1225)
at javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1273)
at javax.swing.JComboBox.contentsChanged(JComboBox.java:1329)
at javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118)
at javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93)
at javax.swing.JComboBox.setSelectedItem(JComboBox.java:578)
at javax.swing.JComboBox.setSelectedIndex(JComboBox.java:624)
at javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:835)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290)
at java.awt.Component.processMouseEvent(Component.java:6516)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:499)
at java.awt.Component.processEvent(Component.java:6281)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4872)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:747)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:706)
at java.awt.EventQueue$3.run(EventQueue.java:704)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:720)
at java.awt.EventQueue$4.run(EventQueue.java:718)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:717)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Solution

  • Again, I would avoid filling my combo box with both ints and Strings. Stick with Integer, and in fact declare your JComboBox as a generic object that uses the Integer as its generic type: JComboBox<Integer>. Add a null for an empty element and then check for null:

    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.*;
    
    public class Foo2 extends JPanel {
       DefaultComboBoxModel<Integer> jcPtIdModel = new DefaultComboBoxModel<>();
       JComboBox<Integer> jcPtIdCombo = new JComboBox<>(jcPtIdModel);
    
       public Foo2(List<Integer> ids) {
          if (ids != null) {
             updateIds(ids);
          }
          add(jcPtIdCombo);
    
          jcPtIdCombo.addItemListener(new MyItemListener());
       }
    
       public void updateIds(List<Integer> ids) {
          jcPtIdModel.removeAllElements();
          jcPtIdModel.addElement(null);
          for (Integer id : ids) {
             jcPtIdModel.addElement(id);
          }
       }
    
       private class MyItemListener implements ItemListener {
          @Override
          public void itemStateChanged(ItemEvent e) {
             //!! if (jcPatientIds.getSelectedItem().equals("")) {
             if (jcPtIdCombo.getSelectedItem() == null) {
                // Some stuff
             } else {
                // Here I am getting ClassCastException
                System.out.println((int) jcPtIdCombo.getSelectedItem());
                // Some other stuff
             }         
          }
       }
    
       private static void createAndShowGui() {
          ArrayList<Integer> items = new ArrayList<>();
          for (int i = 0; i < 10; i++) {
             items.add(i);
          }
    
          Foo2 mainPanel = new Foo2(items);
    
          JFrame frame = new JFrame("Foo2");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    

    Also I see you using setBounds(...) and I strongly advise you not to do this. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.