javaswingjcomboboxjmenubaritemlistener

issue about JComboBox itemListener in two level JMenu


I'm new, but I was searching and now it's time for me to ask you mates. I have this simple app in java, which includes itemListener for JComboBox. I have no idea why but, it doesn't listen, but when i put JComboBox upper in hierarchy it works, and itemListener works fine. Any ideas why it doesn't work in lower level?

import javax.swing.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class Notatnik extends JFrame {

JMenuBar menu;
JMenu tools, fontColor;
JComboBox<String> colors;

    public Notatnik() {
        this.setSize(500, 400);

        menu = new JMenuBar();
        tools = new JMenu("tools");
        fontColor = new JMenu("Font color");
            colors = new JComboBox<String>();
        colors.addItem("red");
        colors.addItem("green");
        colors.addItem("blue");

        colors.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                System.out.println(e.getItem().toString());
            }
        });

        fontColor.add(colors);
        tools.add(fontColor);
        menu.add(tools);
        this.setJMenuBar(menu);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

Solution

  • It is not possible to add a JComboBox to a JMenu component (without destroying the listeners). Therefore, I changed the implementation a bit:

    import java.awt.Color;
    import java.awt.EventQueue;
    
    import javax.swing.*;
    
    public class Stackoverflow {
    
        // Initialize the color to your desired choice.
        private static Color color = Color.RED;
    
        public static void main(final String[] arguments) {
            final JFrame frame = new JFrame("Stackoverflow | Answer");
            EventQueue.invokeLater(() -> {
                final JMenuBar menuBar = new JMenuBar();
                final JMenu menu = new JMenu("Edit");
                // This is just for debugging.
                final JLabel currentColor = new JLabel(color.getRed() + "r " + color.getGreen() + "g " + color.getBlue() + "b");
                final JMenuItem item01 = new JMenuItem("Red");
                final JMenuItem item02 = new JMenuItem("Green");
                final JMenuItem item03 = new JMenuItem("Blue");
                item01.addActionListener((event -> {
                    Stackoverflow.setColor(currentColor, Color.RED);
                }));
                item02.addActionListener((event -> {
                    Stackoverflow.setColor(currentColor, Color.GREEN);
                }));
                item03.addActionListener((event -> {
                    Stackoverflow.setColor(currentColor, Color.BLUE);
                }));
                final JMenu parent = new JMenu("Color");
                parent.add(currentColor);
                parent.add(item01);
                parent.add(item02);
                parent.add(item03);
                menu.add(parent);
                menuBar.add(menu);
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setSize(500, 400);
                frame.setLocationRelativeTo(null);
                frame.setJMenuBar(menuBar);
                frame.setVisible(true);
            });
        }
    
        public static void setColor(final JLabel label, final Color color) {
            // Update the text of the specified JLabel. Edit this part to change the actual font color.
            label.setText(color.getRed() + "r " + color.getGreen() + "g " + color.getBlue() + "b");
            Stackoverflow.color = color;
        }
    }
    

    I know that the code is not tidy or efficient, but it works just fine. Before I forget it, you should definetly visit this article about when to inherit a class.