JOptionPane – 检查用户input,并防止closures,直到条件满足

请有人告诉我是否有一个方便的方法来阻止JOptionPaneclosures后单击确定,除非满足用户input字段的条件?

还是我别无select,只能使用JFrame

我的validation逻辑到目前为止。 似乎不工作,因为button是一次点击某种原因…

 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); 

您可以创build自己的自定义JDialog以在closures或继续之前检查用户input等。 看到这个链接:

停止自动对话框closures

默认情况下,当用户点击一个JOptionPane创build的button时,对话框closures。 但是如果你想在closures对话框之前检查用户的答案呢? 在这种情况下,您必须实现您自己的属性更改侦听器,以便当用户单击button时,对话框不会自动closures。

这是我做的一个例子:

如果您input错误/没有文字,然后点击input一个validation信息将被显示:

在这里输入图像描述

如果您点击X来closures对话框,或者点击取消,也会显示一条validation信息:

在这里输入图像描述

如果input正确的文本(在这种情况下,“大卫”),并input点击一个消息显示和JDialog退出:

在这里输入图像描述

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); } }); } } 

关于停止自动对话框closures的一件事是,它只是帮助,如果你想防止closures或validation,然后closures…基础上的示例代码在该教程的解决scheme,我无法得到validation,并保持开放,如果validation失败。

回想起来,我认为我第一次尝试不起作用的原因可能是因为它使用JOptionPanel.createDialog()(而不是示例代码)。 也许让JOptionPanel创build它自己的JDialog,在事件处理的工作方式上设置了一些“背景”依赖关系…… meh。 无论如何,我已经得到了我想要的:David Kroucamp的代码对我来说非常有用。

我张贴我的解决scheme,因为它处理PropertyChangeEvents不同于大卫,所以这可能是有用的一些人。 你会看到很多代码和他的相同(谢谢大卫)

这个类检查文件存在,并让用户提供一个新的名字或取消。 它在构造函数中使用一些参数来validation用户的input。 validation是if(!Files.exists(rootPathArg.resolve(input))) { // close the dialog }

 class GetPathNameDialog extends JDialog implements ActionListener, PropertyChangeListener { /** * contains the users input */ private JTextField textField; /** * the option pane that holds all fields and controls in this dialog */ private JOptionPane optionPane; /** * label for the left button that represents "OK" */ private String button1Str; /** * label for the right button that represents "Cancel" */ private String button2Str; /** * path containing the named entity to be renamed. */ private Path rootPath; /** * Creates the reusable dialog. */ /** * Creates the dialog, panel and all GUI components, sets up listeners. * * @param rootPath the path where the file or folder we are renaming lives * @param initialText the initial text to display in the text field (ie current name) * @param title title of the JDialog itself * @param textFieldWidth number of columns in the JTextField that will contain the file/folder name * @param promptStr the propmt to display in the panel * @param button1Str the label for the "OK" button * @param button2Str the label for the "Cancel" button */ public GetPathNameDialog(Path rootPath, String initialText, String title, int textFieldWidth, String promptStr, String button1Str, String button2Str) { super((Frame) null, true); // init class variables this.rootPath = rootPath; this.button1Str = button1Str; this.button2Str = button2Str; setTitle(title); textField = new JTextField(textFieldWidth); textField.setText(initialText); //Create an array of the text and components to be displayed. Object[] array = {promptStr, textField}; //Create an array specifying the number of dialog buttons //and their text. Object[] options = {button1Str, button2Str}; //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 INPUT_VALUE_PROPERTY textField.addActionListener(this); // Register an event handler that reacts to option pane state changes. optionPane.addPropertyChangeListener(this); // tell this dialog to display close to the current mouse pointer setLocation(MouseInfo.getPointerInfo().getLocation()); pack(); } /** * This method handles events for the text field. */ @Override public void actionPerformed(ActionEvent e) { // this will fire a INPUT_VALUE_PROPERTY PropertyChangeEvent... takes the user input to the validaton code in the property handler optionPane.setInputValue(textField.getText()); } /** * This method reacts to property changes. */ @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (isVisible() && (e.getSource() == optionPane)) { // the VALUE_PROPERTY is not the same as the INPUT_VALUE_PROPERTY. we make use of the INPUT_VALUE_PROPERTY to carry our data // but the JOptionPane uses the VALUE_PROPERTY for other stuff if (JOptionPane.VALUE_PROPERTY.equals(prop)) { // newValues delivered by VALUE_PROPERTY PropertyChangeEvent can be the actual labels of the button clicked, // that's sooo counter-intuitive to me, but it's how we know which button got clicked if (button1Str.equals(e.getNewValue())) { // "OK" functionality... // ...this will fire the event that takes the user input to the validation code optionPane.setInputValue(textField.getText()); } else if (button2Str.equals(e.getNewValue())) { // "CANCEL" functionality optionPane.setInputValue(null); exit(); } } else if (JOptionPane.INPUT_VALUE_PROPERTY.equals(prop)) { Object value = optionPane.getInputValue(); // null or empty strings in the text field (ie in the INPUT_VALUE_PROPERTY) are ignored if (null != value && ((String) value).length() > 0) { // here is the validation code if (Files.exists(rootPath.resolve(textField.getText()))) { // already exists, tell user JOptionPane.showMessageDialog(this, "Sorry, " + rootPath.resolve(textField.getText()).toString() + " already exists.\n\n Please enter another name.", "OK", JOptionPane.ERROR_MESSAGE); // Make sure PropertyChangeEvent will fire next time... // ...PropertyChangeEvents don't fire in setInputValue(newVal)... // ...if newVal is equal to the current value, but if the user clicks... // ...button 1 or hits enter in the text field without changing his text,... // ...we still want to fire another event... // ...so we reset the property without changing the text in the textField optionPane.setInputValue(null); } else { // does not exist.. we are keeping the users input... // ... it gets delivered to the user in getInputValue() exit(); } } } } } /** * returns the users's validated input. Validated means !Files.exists(rootPath.resolve(input)). * * @return the text entered by the user, UNINITIALIZED_VALUE if the user X closed, null the user canceled */ public Object getInputValue() { return optionPane.getInputValue(); } /** * closes the dialog and triggers the return from setVisible() */ public void exit() { dispose(); } } 

调用它的代码是:

  GetPathNameDialog tempD = new GetPathNameDialog( someFolderPath, "theFileNameThatMustBeChanged.txt", "Change File Name", 50, "someFolderPath already contains a file named theFileNameThatMustBeChanged.txt." + ".\n\nPlease enter a different file name:", "Copy the file with the new name", "Do not copy the file"); tempD.setVisible(true); Object inputObj = tempD.getInputValue(); String input = (inputObj == JOptionPane.UNINITIALIZED_VALUE || null == inputObj ? "" : (String) inputObj); if (input.length() > 0) { // we now have a new file name. go ahead and do the copy or rename or whatever... }