Search code examples
javaswingjoptionpane

How do I make a JOptionPane dropdown that has a preset option that is not choosable?


Say I am making a program that keeps track of people's favorite food. I have a dropdown, as such:

String foods = { "Pizza", "Burgers", "Pasta", "Bacon" };
String favoriteFood = JOptionPane.showInputDialog(null, "What is your favorite food?", "Choice", JOptionPane.QUESTION_MESSAGE, null, foods, foods[0]));
JOptionPane.showMessageDialog(null, favoriteFood);
            

How do I make a part in the dropdown that is like "Choose now...", but if you click the "Choose now...", it doesn't become your choice? Thank you!


Solution

  • You may do it like this

    String[] foods = { "Pizza", "Burgers", "Pasta", "Bacon" };
    JComboBox<String> cb = new JComboBox<String>(foods);
    cb.getModel().setSelectedItem("Choose now...");
    
    cb.addHierarchyListener(hEv -> {
        if((hEv.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && cb.isShowing()) {
            JButton ok = SwingUtilities.getRootPane(cb).getDefaultButton();
            ok.setEnabled(cb.getSelectedIndex() >= 0);
            cb.addActionListener(aEv -> ok.setEnabled(cb.getSelectedIndex() >= 0));
    }   });
    
    JPanel p = new JPanel(new GridLayout(0, 1, 0, 8));
    p.add(new JLabel("What is your favorite food?"));
    p.add(cb);
    
    int choice = JOptionPane.showConfirmDialog(null,
        p, "Choice", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
    
    JOptionPane.showMessageDialog(null,
        choice == JOptionPane.OK_OPTION? cb.getSelectedItem(): "no choice");
    

    The first challenge is to set a (pre)selected value that is not part of the selectable choices. When you call setSelectedItem on a non-editable JComboBox, it will reject any values outside the model. However, we can set the selected value on the model directly, like in cb.getModel().setSelectedItem("Choose now...");

    Then, to ensure that we won’t confuse this initial selection with an actual selection, we have to disable the “Ok” button until a choice from the list has been made (cb.getSelectedIndex() >= 0). To get the “Ok” button itself, we wait until the entire AWT hierarchy has been constructed and get the default button.