Search code examples
javaswinguser-interfacemenu

How to use a JCombobox in JMenu?


I want to add a Combobox to my JMenu but its not working properly. When I click it the menu closes.

I tried to add a JMenuItem and a JPanel with the combobox to the menu but neither worked.

public class Combo extends JMenuBar{

    public Combo(){
        this.setBackground(Color.DARK_GRAY);
        this.setForeground(Color.WHITE);
        this.setBorder(null);
        this.add(createCombobox());
    }

    

    private JMenu createCombobox() {
        JMenu menu = new JMenu("test");
        JLabel box = new JLabel("Color");
        String[] colors = {"blue", "green", "yellow"};

        JComboBox<String> comboBox = new JComboBox<>(colors);

        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.setBorder(new MatteBorder(0, 5, 0, 0, Color.DARK_GRAY));
        panel.setBackground(Color.DARK_GRAY);
        panel.add(box, BorderLayout.CENTER);
        panel.add(comboBox, BorderLayout.EAST);

        menu.add(panel);

        return menu;
    }
    
}



Solution

  • This idea seems like an anti pattern to me - it doesn't really make sense when you consider that you could use a sub menu to effectively get the same workflow in a more expected and user acceptable way.

    (There's also a million or more technical issues why I wouldn't even try and use a JCombobox this way, but lets stick with the fact that there is a pre-existing acceptable UX workflow)

    Take a look at How to Use Menus and How to Use Actions for some more details.

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import javax.swing.AbstractAction;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    
    public class Test {
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JTextArea textArea = new JTextArea("A long time ago, in a galaxy far, far away...", 10, 30);
    
            public TestPane() {
                JMenuBar menuBar = new JMenuBar();
                JMenu menu = new JMenu("Text");
                menuBar.add(menu);
    
                JMenu color = new JMenu("Color");
                menu.add(color);
    
                ColorAction.Observer observer = new ColorAction.Observer() {
                    @Override
                    public void didSetColor(ColorAction action, Color color) {
                        textArea.setForeground(color);
                    }
                };
    
                color.add(new ColorAction("Blue", Color.BLUE, observer));
                color.add(new ColorAction("Green", Color.GREEN, observer));
                color.add(new ColorAction("Yellow", Color.YELLOW, observer));
    
                setLayout(new BorderLayout());
    
                add(menuBar, BorderLayout.NORTH);
                add(new JScrollPane(textArea));
            }
        }
    
        public class ColorAction extends AbstractAction {
            private static Observer Observer;
    
            public interface Observer {
                public void didSetColor(ColorAction action, Color color);
            }
    
            private Color color;
            private Observer observer;
    
            public ColorAction(String text, Color color, Observer observer) {
                super(text);
                this.color = color;
                this.observer = observer;
            }
    
            public Color getColor() {
                return color;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                if (observer == null) {
                    return;
                }
                observer.didSetColor(this, getColor());
            }
        }
    }