0

I'm trying to use JCombobox inside the JPopupMenu, but without success, popup becomes visible when user clicks the label,

 label = new JLabel();
 label.addMouseListener(this);

this is the label code, with mouse listener, on mousePressed and mouseClicked events it does display and hide popup menu, inside the menu I have JPanel which contains ButtonGroup, click on buttons displays different JPanel's in the center of the panel, short exmaple of panel and popup menu code looks like this

    popupPanel = new JPanel();
    popupPanel.setLayout(new BorderLayout());


    menu = new JPopupMenu();
    menu.add(BorderLayout.CENTER, popupPanel);
    menu.pack();
    menu.addPopupMenuListener(this);

popup panel contains button groups as i mentioned above, when one of the buttons is clicked it displays

    color_combo_panel = new JPanel();
    color_combo_panel.setLayout(new GridBagLayout());


    color_combo = new JComboBox<>();
    color_combo.addItem(Color.RED.toString());
    color_combo.addItem(Color.BLUE.toString());
    color_combo.addItem(Color.CYAN.toString());
    color_combo.setRenderer(new ColorRenderer());

panel containing JCombobox, problem starts from here, when I click on combo box to select the color, JPopupMenu gets closed, on the ather hand JCombobox selection does nothing, my question is, how can I force popup menu to stay visible, with mouse and popup listeners i have forced it to stay visible, but as a result I get IllegalComponentStateException, component must be shown on the screen, I found problem similar to mine, but it do not provide relevant solution, plus this behavior is submitted as a BUG here.

will much appreciate any useful advice

EDIT minimal reproducible example asked by @camickr

public class PopupTest {

public static void main(String[] args) {

    JFrame frame = new JFrame();
    frame.setSize(new Dimension(500, 500));
    frame.setLayout(new GridBagLayout());
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.add(new ColorCombo());
    frame.setVisible(true);


}


static class ColorCombo extends JComboBox {

    private static final long serialVersionUID = 2L;

    public ColorCombo() {
        setPreferredSize(new Dimension(200, 30));
    }

    @Override
    public void updateUI() {
        ComboBoxUI cui = (ComboBoxUI) UIManager.getUI(this);
        if (cui instanceof MetalComboBoxUI) {
            cui = new MetalBrushComboBoxUI();
        } else {
            cui = new BasicBrushComboboxUI();
        }
        setUI(cui);
    }

    class MetalBrushComboBoxUI extends MetalComboBoxUI {
        @Override
        protected ComboPopup createPopup() {
            return new ColorPopup(comboBox);
        }
    }

    class BasicBrushComboboxUI extends BasicComboBoxUI {

        @Override
        protected ComboPopup createPopup() {
            return new ColorPopup(comboBox);
        }
    }


    class ColorPopup extends MouseAdapter implements ComboPopup, ActionListener {

        private JList list = new JList();
        private JComboBox comboBox;
        private JPopupMenu popupMenu;
        private JPanel container, first_color_panel;


        public ColorPopup(JComboBox comboBox) {
            this.comboBox = comboBox;

            container = new JPanel();
            container.setLayout(new BorderLayout());

            JToggleButton first_button = new JToggleButton();
            first_button.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2, false));
            first_button.setPreferredSize(new Dimension(20, 20));
            first_button.setBackground(Color.WHITE);
            first_button.addActionListener(this);
            first_button.setActionCommand("color1");


            ButtonGroup buttonGroup = new ButtonGroup();
            buttonGroup.add(first_button);


            JPanel northPanel = new JPanel();
            northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
            northPanel.add(first_button);

            first_color_panel = new JPanel();
            first_color_panel.setLayout(new GridBagLayout());

            JComboBox<String> color_combo = new JComboBox<>();
            color_combo.setPreferredSize(new Dimension(120, 30));
            for (String color : getColors().keySet())
                color_combo.addItem(color);
            color_combo.setRenderer(new ColorRenderer());
            color_combo.addActionListener(this);
            color_combo.setActionCommand("color1_ground");

            first_color_panel.add(color_combo);

            container.add(northPanel, BorderLayout.NORTH);

            popupMenu = new JPopupMenu();
            popupMenu.add(BorderLayout.CENTER, container);
        }


        @Override
        public void actionPerformed(ActionEvent e) {
            boolean isSet = container.getComponents().length == 2;
            if ("color1".equals(e.getActionCommand())) {
                if (isSet)
                    container.remove(1);
                container.add(first_color_panel, BorderLayout.CENTER);
            }
            container.revalidate();
            popupMenu.repaint();
        }

        @Override
        public void show() {
            this.container.setPreferredSize(new Dimension(this.comboBox.getWidth(), 100));
            popupMenu.add(BorderLayout.CENTER, container);
            popupMenu.pack();
            popupMenu.show(this.comboBox, 0, this.comboBox.getHeight());
        }

        @Override
        public void hide() {
            popupMenu.setVisible(false);
        }

        @Override
        public boolean isVisible() {
            return popupMenu.isVisible();
        }

        @Override
        public JList getList() {
            return list;
        }

        @Override
        public MouseListener getMouseListener() {
            return this;
        }

        @Override
        public MouseMotionListener getMouseMotionListener() {
            return this;
        }

        @Override
        public KeyListener getKeyListener() {
            return null;
        }

        @Override
        public void uninstallingUI() {

        }

        @Override
        public void mouseClicked(MouseEvent e) {
            comboBox.requestFocus();
            toggle();
        }


        private void toggle() {
            if (isVisible()) {
                hide();
            } else {
                show();
            }

        }

        private Map<String, Color> getColors() {
            Map<String, Color> colors = new HashMap<>();
            colors.put("Red", Color.RED);
            colors.put("blue", Color.BLUE);
            colors.put("green", Color.GREEN);
            colors.put("Yellow", Color.YELLOW);
            return colors;
        }

        class ColorRenderer extends JPanel implements ListCellRenderer<String> {


            @Override
            public Component getListCellRendererComponent(JList<? extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) {
                JPanel panel = new JPanel();
                panel.setLayout(new BorderLayout(3, 3));
                panel.setBorder(BorderFactory.createCompoundBorder(getBorder(),
                        BorderFactory.createEmptyBorder(0, 0, 3, 0)));

                JLabel label = new JLabel();
                label.setOpaque(true);
                label.setPreferredSize(new Dimension(20, label.getHeight()));
                label.setBackground(getColors().get(value));

                JLabel text = new JLabel();
                text.setText(value);

                panel.add(label, BorderLayout.WEST);
                panel.add(text, BorderLayout.CENTER);

                return panel;
            }
        }

    }
}}
George Weekson
  • 483
  • 3
  • 13
  • @Abra no, `Jdialog` is not a solution, i can manage to do similar logic with many different way, to put, `JColorChooser` instead of `JCombobox` for example, but using a `JCombobox` is must in this situation – George Weekson Dec 07 '20 at 11:44
  • 1
    I meant a `JDialog` that contains a `JComboBox` rather than a `JPopupMenu` that contains a `JComboBox`. – Abra Dec 07 '20 at 11:46
  • thats intresting, i'll give a try – George Weekson Dec 07 '20 at 11:52
  • @Abra you idea did the great job, replaced popup menu with jdialog, but it is still a workaround not the solution. – George Weekson Dec 07 '20 at 15:16
  • 2
    That is not how a JPopupMenu was designed to be used. That is you don't add the popup menu to a panel. A popup menu is meant to be displayed temporarily and then closed. If you want something to be permanently displayed, then use a JDialog as already suggested. See: [Bringing Up a Popup Menu](https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html#popup). Post a proper [mre] demonstrating the problem. – camickr Dec 07 '20 at 15:27
  • @camickr have added minimal reproducible example – George Weekson Dec 07 '20 at 16:39
  • Sorry, I have no idea what you are attempting to do. I have no idea why you would attempt to have a popup of a combox inside of the combo box popup. The point of using a combo box is to select an item from the combo box. Not sure why you need another popup. The UI doesn't make any sense to me. – camickr Dec 07 '20 at 17:34
  • have replaced it with `Jdialog` already as Abra adviced and it works, I'm using it on `JTable` cell, when user clicks on cell, drop down menu opens with panel inside, where user can manipulate with cell appearance, format etc. I know it does not make any sense, and it can be done with using other components much more clearer and fancy way, but that's what my client want and i do not have chose to do it my way – George Weekson Dec 07 '20 at 18:15

0 Answers0