JOptionPane - check user input and prevent from closing until conditions are met

Please can someone tell me if there is a convenient way of prevent JOptionPane from closing upon clicking OK unless the conditions for user input fields are met?

Or do I have no choice but to use JFrame?

My validation logic so far. Doesn't seem to work because the buttons are one-time clickable to some reason...

final JDialog dialog3 = new JDialog(OmniGUI.getFrame(), "Create new Node - id:" + newNodeID);
dialog3.setContentPane(theOPane);
dialog3.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

theOPane.addPropertyChangeListener(new PropertyChangeListener(){
   public void propertyChange(PropertyChangeEvent e) {

       if(e.getSource() == theOPane){
           String val = (String) ((JOptionPane) e.getSource()).getValue();

           if(val=="Create"){
               System.out.println("Checking content");                      

               if(!valid){
                   System.out.println("closing the window");    

                   dialog3.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                   dialog3.removeAll();
                   dialog3.dispatchEvent(new WindowEvent(dialog3, WindowEvent.WINDOW_CLOSING));
               }

           }
       }
   }    
});

    dialog3.setLocation(p);
    dialog3.pack();
    dialog3.setVisible(true);

Solution 1:

You can create your own Custom JDialog to check user input etc before closing or moving on. See this link:

Stopping Automatic Dialog Closing

By default, when the user clicks a JOptionPane-created button, the dialog closes. But what if you want to check the user's answer before closing the dialog? In this case, you must implement your own property change listener so that when the user clicks a button, the dialog does not automatically close.

Here is an example I made:

If you type wrong/no text and click Enter a validation message will be displayed:

enter image description here

If you click X to close Dialog or click Cancel a validation message will be shown also:

enter image description here

If correct text is entered (in this case "David") and enter is clicked a message is shown and JDialog is exited:

enter image description here

CustomDialog.java:

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

class CustomDialog extends JDialog
        implements ActionListener,
        PropertyChangeListener {

    private String typedText = null;
    private JTextField textField;
    private String magicWord;
    private JOptionPane optionPane;
    private String btnString1 = "Enter";
    private String btnString2 = "Cancel";

    /**
     * Returns null if the typed string was invalid; otherwise, returns the
     * string as the user entered it.
     */
    public String getValidatedText() {
        return typedText;
    }

    /**
     * Creates the reusable dialog.
     */
    public CustomDialog(Frame aFrame, String aWord) {
        super(aFrame, true);

        magicWord = aWord.toUpperCase();
        setTitle("Quiz");

        textField = new JTextField(10);

        //Create an array of the text and components to be displayed.
        String msgString1 = "What was Dr. SEUSS's real last name?";
        String msgString2 = "(The answer is \"" + magicWord
                + "\".)";
        Object[] array = {msgString1, msgString2, textField};

        //Create an array specifying the number of dialog buttons
        //and their text.
        Object[] options = {btnString1, btnString2};

        //Create the JOptionPane.
        optionPane = new JOptionPane(array,
                JOptionPane.QUESTION_MESSAGE,
                JOptionPane.YES_NO_OPTION,
                null,
                options,
                options[0]);

        //Make this dialog display it.
        setContentPane(optionPane);

        //Handle window closing correctly.
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        //Ensure the text field always gets the first focus.
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent ce) {
                textField.requestFocusInWindow();
            }
        });

        //Register an event handler that puts the text into the option pane.
        textField.addActionListener(this);

        //Register an event handler that reacts to option pane state changes.
        optionPane.addPropertyChangeListener(this);
        pack();
    }

    /**
     * This method handles events for the text field.
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        optionPane.setValue(btnString1);
    }

    /**
     * This method reacts to state changes in the option pane.
     */
    @Override
    public void propertyChange(PropertyChangeEvent e) {
        String prop = e.getPropertyName();

        if (isVisible()
                && (e.getSource() == optionPane)
                && (JOptionPane.VALUE_PROPERTY.equals(prop)
                || JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
            Object value = optionPane.getValue();

            if (value == JOptionPane.UNINITIALIZED_VALUE) {
                //ignore reset
                return;
            }

            //Reset the JOptionPane's value.
            //If you don't do this, then if the user
            //presses the same button next time, no
            //property change event will be fired.
            optionPane.setValue(
                    JOptionPane.UNINITIALIZED_VALUE);

            if (btnString1.equals(value)) {
                typedText = textField.getText();
                String ucText = typedText.toUpperCase();
                if (magicWord.equals(ucText)) {
                    JOptionPane.showMessageDialog(this, "Correct answer given");
                    exit();
                } else {
                    //text was invalid
                    textField.selectAll();
                    JOptionPane.showMessageDialog(this,
                            "Sorry, \"" + typedText + "\" "
                            + "isn't a valid response.\n"
                            + "Please enter "
                            + magicWord + ".",
                            "Try again",
                            JOptionPane.ERROR_MESSAGE);
                    typedText = null;
                    textField.requestFocusInWindow();
                }
            } else { //user closed dialog or clicked cancel
                JOptionPane.showMessageDialog(this, "It's OK.  "
                        + "We won't force you to type "
                        + magicWord + ".");
                typedText = null;
                exit();
            }
        }
    }

    /**
     * This method clears the dialog and hides it.
     */
    public void exit() {
        dispose();
    }

    public static void main(String... args) {
        //create JDialog and components on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CustomDialog(null, "David").setVisible(true);
            }
        });
    }
}