2012-10-24 68 views
8

請有人告訴我是否有一種方便的方法來防止JOptionPane在單擊確定後關閉,除非滿足用戶輸入字段的條件?我不得不使用JFrameJOptionPane - 檢查用戶輸入,並防止關閉,直到條件滿足

我的驗證邏輯到目前爲止。似乎沒有工作,因爲按鈕是一次性點擊某種原因...

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

您正在使用什麼方法? showConfirmDialog,showInputDialog? –

+0

我使用的JDialog的createDialog或setContentPane,但我可以用任何東西去,如果將工作 – bioMind

回答

20

您可以創建自己的自定義JDialog關閉或移動之前檢查用戶輸入等。請參閱此鏈接:

Stopping Automatic Dialog Closing

默認情況下,當用戶點擊一個JOptionPane的創建按鈕時, 對話框關閉。但是如果您想在關閉對話框之前檢查用戶的答案,怎麼辦?在這種情況下,您必須實現您自己的屬性 更改偵聽器,以便當用戶單擊按鈕時,對話框不會自動關閉 。

這裏是我做了一個例子:

如果輸入錯誤的/沒有文字,然後點擊回車後會顯示一條驗證消息:

enter image description here

如果單擊X到關閉對話框或單擊取消驗證消息也將顯示:

enter image description here

如果正確的文本輸入(在這種情況下, 「大衛」),並輸入被點擊的消息顯示,並JDialog退出:

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

沒錯,這就是我一直在尋找。非常感謝! – bioMind

+0

完美!我建議改變的唯一事情是:使用'optionPane.addPropertyChangeListener(「價值」,這一點);'以提高性能。 – Daniel

+1

+1,因爲我用它......謝謝大衛。我已爲我的下面,因爲它是略有不同,可能是有用的 – PMorganCA

0

關於Stop Automatic Dialog Closing的一件事是,它只有在你想阻止關閉或驗證然後關閉的時候纔有幫助......基於該教程中示例代碼的解決方案,我如果驗證失敗,則無法驗證它並保持打開狀態。回想起來,我認爲我第一次嘗試不起作用的原因可能是因爲它使用了JOptionPanel.createDialog()(不是示例代碼所做的)。也許讓JOptionPanel創建它自己的JDialog,可以爲事件處理的工作方式設置一些「背景」依賴關係...... meh。無論如何,我已經得到了我想要的東西:David Kroucamp的代碼對我非常有用。

我發佈了我的解決方案,因爲它處理PropertyChangeEvents的方式與David不同,因此它可能對某些人有用。你會看到很多代碼與他的相同(謝謝大衛)

這個類檢查文件存在並讓用戶提供一個新的名字或取消。它在構造函數中使用一些參數來驗證用戶的輸入。驗證是 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 (i.e. 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... 
    } 
+0

*我無法得到它來驗證,如果驗證失敗,保持開放*嗯林不知道你的意思,我只是再次測試代碼和@DavidKroukamp你的代碼工作得很好,遺憾的混亂正常工作... –

+0

。我無法工作的是我最初的嘗試,它由Java教程中示例代碼的一部分剪切和粘貼組成。 – PMorganCA

相關問題