Search code examples
javaswingfocusjoptionpanenimbus

With Nimbus laf, my JOptionPane doesn't get focus when called from a combobox ItemEvent


hope you can help.

I'm hoping this isn't just a bug and that we can solve it.

I currently have a Java program with a JComboBox. When the user changes the selected item in the combo box a JOptionPane appears to allow the user to confirm the change.

When the new selection is made in the combo box, the JOptionPane appears as desired but you have to click it twice to use it. That is, click it once to gain focus and then click the button you want to use. Another method is to click within the bounds of the program's GUI (behind the optionPane) and then click the button.

No Exceptions occur, and the program functions as normal once the buttons are clicked.

This functionality only occurs using the Nimbus LookAndFeel and not with the native macos laf (building on mac, haven't tested on windows) but I need to use nimbus for other reasons.

I've been looking through the Nimbus issue tracking but have yet to find the fault.

I have JButton which calls the SAME code (ie JOptionPane.showConfirmDialog(...) and this works perfectly, it's just when it's called from the action of the combo box.

Really hope you can help! Cheers in advance!

import javax.swing.UIManager.*;
import javax.swing.*;

public class TestJavaProblem extends JFrame {
    JComboBox jComboBox1;

    public TestJavaProblem() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        initComponents();
    }

    private void initComponents() {
        jComboBox1 = new JComboBox();

        //give it some values
        jComboBox1.setModel(new DefaultComboBoxModel(new String[] { "1", "2"}));

        //add listener
        jComboBox1.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) { fireTask(evt);}
        });

        this.add(jComboBox1);
        pack();
    }

    private void fireTask(java.awt.event.ItemEvent evt) {
        if (evt.getStateChange() == 1) { //so dialog fires only once
            int i = JOptionPane.showConfirmDialog(jComboBox1, "Message Text", "Title", JOptionPane.OK_CANCEL_OPTION);
            System.out.println("Result:" + i);
        }
    }

    public static void main(String args[]) {
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                break;
                }
            }
        } catch (Exception e) {/*no nimbus*/}

        new TestJavaProblem().setVisible(true);
    }
}

Solution

  • don't use magic number,

    if (evt.getStateChange() == 1) { //so dialog fires only once
    

    or

    int i = JOptionPane.showConfirmDialog(jComboBox1,
    

    here is workaround code, but seems like required for MetalLookAndFeel, Substance on Windows OS

    import javax.swing.UIManager.*;
    import javax.swing.*;
    import javax.swing.event.PopupMenuEvent;
    import javax.swing.event.PopupMenuListener;
    
    public class TestJavaProblem extends JFrame {
    
        private static final long serialVersionUID = 1L;
        private JComboBox jComboBox1;
        private boolean boloComboBox = false;
    
        public TestJavaProblem() {
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            initComponents();
        }
    
        private void initComponents() {
            jComboBox1 = new JComboBox();
            jComboBox1.setModel(new DefaultComboBoxModel(new String[]{"1", "2"}));
            jComboBox1.addItemListener(new java.awt.event.ItemListener() {
    
                @Override
                public void itemStateChanged(final java.awt.event.ItemEvent evt) {
                    if (jComboBox1.isPopupVisible()) {
                        jComboBox1.setPopupVisible(false);
                        SwingUtilities.invokeLater(new Runnable() {
    
                            @Override
                            public void run() {
                                fireTask(evt);
                            }
                        });
                    }
                }
            });
            jComboBox1.addPopupMenuListener(new PopupMenuListener() {
    
                @Override
                public void popupMenuCanceled(PopupMenuEvent e) {
                    System.out.println(e.getSource());
                }
    
                @Override
                public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                    System.out.println(e.getSource());
                }
    
                @Override
                public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                    System.out.println(e.getSource());
                }
            });
            add(jComboBox1);
            pack();
        }
    
        private void fireTask(java.awt.event.ItemEvent evt) {
            if (evt.getStateChange() == 2) {
                int i = JOptionPane.showConfirmDialog(jComboBox1, 
                    "Message Text", "Title", JOptionPane.OK_CANCEL_OPTION);
                System.out.println("Result:" + i);
            }
        }
    
        public static void main(String args[]) {
            try {
                for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (Exception e) {
            }
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new TestJavaProblem().setVisible(true);
                }
            });
        }
    }