Search code examples
javaswingjcombobox

JComboBox not updating after item selection


I have an error with some code (i'll show it below) where when the user picks an item from the JComboBox, the program doesn't update and thinks that there's no item selected. It's worth mentioning that .setSelectedIndex does update and make the program know that the selected item changed, even though it's a result of it being changed by .setSelectedIndex Here's the code: (I'll put all the project's code here as i have no idea what a minimal reproducible example would be in this case, as I don't know what's causing the problem)

package sample;

import sun.security.mscapi.CPublicKey;

import javax.swing.*;
import java.awt.*;
import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    static final int WIDTH = 600;
    static final int HEIGHT = 400;
    public static final String TITLE = "Schedule Maker";

    public JButton start;

    //Hour array
    private int[] hours = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,};
    private JTextField heading = new JTextField("Hours");
    private JTextField selectedHour = new JTextField(15);
    private JComboBox hourBox = new JComboBox();

    public Main() {
        for (int i = 0; i < hours.length; i++) {
            hourBox.addItem(hours[i]);
        }
        hourBox.setSelectedIndex(-1);

        heading.setEditable(false);
        hourBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                selectedHour.setText("You selected : " + ((JComboBox) event.getSource()).getSelectedItem());
            }
        });

        int item = hourBox.getSelectedIndex();

        this.setLayout(new FlowLayout());
        this.add(heading);
        this.add(selectedHour);
        this.add(hourBox);
    }

    public void create() {

        start = new JButton();

        JFrame frame = new Main();
        JPanel panel = new JPanel();

        frame.setTitle("Title (I'm great at names i know)");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);
        frame.setVisible(true);
        frame.pack();
        frame.setTitle("TITLE");
        frame.setSize(300, 200);
        frame.setResizable(true);
        frame.setVisible(true);
        frame.add(panel);
        frame.add(start);
        start.setText("Select an hour");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ActionListener click = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == start) {
                    if (hourBox.getSelectedIndex() == -1) {
                        start.setText("Please select an hour");
                    } else {
                        start.setText("Some text since the rest of the program is not done yet");
                    }
                }
            }

        };

        start.addActionListener(click);

    }

    public static void main(String args[]) {
        Main m = new Main();
        m.create();
    }
}





Solution

  • I see several problems with your code. Let me list them sorted from problematic bugs to, well, style issues ;)

    • You are creating two instances of your class. The first one in the main method, the second one in the create() method. The hourBox you refer to in create() is not the same object you display in your JFrame! It's all very tangled. This is what causes your problem! Allow me to tidy this up ... the following points are additional issues I see, but they're not related to your problem. I list them anyway to explain the changes I made.
    • JComboBox is using a generic type, so you should specify it: JComboBox<Integer> hourBox = new JComboBox<Integer>();
    • There's a lot of unnecessary code, like duplicate calls of setVisible()/setTitle()/setSize()/setDefaultCloseOperation() or just unused objects like panel.
    • You don't need a full array of int values to get your hours into the combo box. See the code below!

    Trying to apply these thoughts to your code, I come up with this:

    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    public class Main extends JFrame {
    
        private static final long serialVersionUID = 8333256750721907342L;
        
        static final int WIDTH = 600;
        static final int HEIGHT = 400;
        
        public static final String TITLE = "Schedule Maker";
        private static final int HOURS = 24;
    
        
        public Main() {
            
            this.setTitle(TITLE);
            this.setResizable(true);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLayout(new FlowLayout());
            
            JTextField selectedHour = new JTextField(15);
            JComboBox<Integer> hourBox = new JComboBox<Integer>();
            
            for (int i = 1; i <= HOURS; i++) {
                hourBox.addItem(i); // add hour to combo box
            }
            
            hourBox.setSelectedIndex(-1);
            hourBox.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    selectedHour.setText(
                            "You selected : " + hourBox.getSelectedItem());
                    setTitle("HOUR: " + hourBox.getSelectedItem());
                }
            });
    
            //int item = hourBox.getSelectedIndex();
    
            this.add(new JTextField("Hours"));
            this.add(selectedHour);
            this.add(hourBox);
            
            JButton start = new JButton();
            start.setText("Select an hour");
            this.add(start);
            
            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource() == start) {
                        if (hourBox.getSelectedIndex() == -1) {
                            start.setText("Please select an hour");
                        } else {
                            start.setText("gud boi!");
                        }
                    }
                }
            });
            
            this.pack();
            this.setSize(300, 200);
            this.setLocationRelativeTo(null); // center window on screen
            this.setVisible(true);
        }
    
        
        public static void main(String args[]) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
        }
        
    }
    

    ... it works as expected.