2012-10-24 22 views
8

Xin vui lòng ai đó có thể cho tôi biết nếu có cách thuận tiện để ngăn chặn JOptionPane kết thúc khi nhấp vào OK trừ khi điều kiện cho các trường nhập của người dùng được đáp ứng?JOptionPane - kiểm tra đầu vào của người dùng và ngăn không cho đến khi các điều kiện được đáp ứng

Hoặc tôi không còn cách nào khác ngoài việc sử dụng JFrame?

Logic xác thực của tôi cho đến thời điểm này. Không có vẻ để làm việc vì các nút là một lần nhấp được một số lý do ...

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

phương pháp gì bạn đang sử dụng? showConfirmDialog, showInputDialog? –

+0

Tôi đang sử dụng JDialog của createDialog hoặc setContentPane nhưng tôi có thể đi với bất cứ điều gì nếu nó sẽ làm việc – bioMind

Trả lời

20

Bạn có thể tạo tùy chỉnh của riêng bạn JDialog để kiểm tra đầu vào người sử dụng vv trước khi đóng cửa hoặc di chuyển trên. Xem liên kết này:

Stopping Automatic Dialog Closing

Theo mặc định, khi người dùng nhấp vào một nút JOptionPane tạo, các đóng cửa hộp thoại. Nhưng nếu bạn muốn kiểm tra câu trả lời của người dùng trước khi đóng hộp thoại? Trong trường hợp này, bạn phải triển khai thuộc tính của riêng mình trình nghe thay đổi để khi người dùng nhấp vào nút, hộp thoại sẽ không tự động đóng.

Dưới đây là một ví dụ tôi đưa ra:

Nếu bạn gõ sai/không có văn bản và nhấp Enter nhắn xác nhận sẽ được hiển thị:

enter image description here

Nếu bạn bấm X để Hộp thoại đóng hoặc nhấp vào Hủy thông báo xác thực cũng sẽ được hiển thị:

enter image description here

Nếu văn bản nhập đúng (trong trường hợp này "David") và nhập được nhấp một thông điệp được hiển thị và JDialog được thoát:

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

Yep, đó là những gì tôi đang tìm kiếm. Cảm ơn rất nhiều! – bioMind

+0

Hoàn hảo! Điều duy nhất tôi khuyên bạn nên thay đổi là: sử dụng 'optionPane.addPropertyChangeListener (" value ", this);' để cải thiện hiệu năng. – Daniel

+1

+1 vì điều này vì tôi đã sử dụng nó ... cảm ơn David. Tôi đã đăng của tôi dưới đây bởi vì nó hơi khác nhau và có thể hữu ích – PMorganCA

0

Một điều về Stop Automatic Dialog Closing là nó chỉ giúp nếu bạn muốn ngăn chặn đóng hoặc xác thực và sau đó đóng ... dựa trên giải pháp trên mã mẫu trong hướng dẫn đó, tôi không thể nhận được nó để xác nhận và ở lại mở nếu xác nhận không thành công.

Nhìn lại, tôi nghĩ lý do nỗ lực đầu tiên của tôi không hoạt động có thể là do nó sử dụng JOptionPanel.createDialog() (không phải mã ví dụ đã làm). Có lẽ để cho JOptionPanel tạo ra JDialog của riêng nó thiết lập một số phụ thuộc "nền" trong cách xử lý sự kiện làm việc ... meh. Trong mọi trường hợp, tôi đã có những gì tôi muốn bây giờ: mã của David Kroucamp rất hữu ích với tôi.

Tôi đăng giải pháp của mình vì giải pháp này xử lý PropertyChangeEvents khác với David nên có thể hữu ích đối với một số người. Bạn sẽ thấy rằng nhiều mã giống hệt với mã (nhờ David)

Lớp này kiểm tra sự tồn tại của tệp và cho phép người dùng cung cấp tên mới hoặc hủy.Phải mất một số arg trong hàm khởi tạo mà nó sử dụng để xác thực đầu vào của người dùng. Xác nhận là 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(); 
    } 
} 

Mã này để gọi nó là:

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

* Tôi không thể làm cho nó xác nhận và ở lại mở nếu xác nhận thất bại * hmm Im không chắc chắn những gì bạn có nghĩa là tôi chỉ cần thử nghiệm mã một lần nữa và hoạt động tốt ... –

+0

@DavidKroukamp mã của bạn làm việc tốt, xin lỗi vì sự nhầm lẫn. Những gì tôi không thể làm việc là nỗ lực ban đầu của tôi, trong đó bao gồm một cắt và dán từ một phần của mã ví dụ trong hướng dẫn Java. – PMorganCA