2012-08-01 33 views
5

Tôi gặp rắc rối với chiếc mặt nạ trong một JFormattedTextFieldrắc rối với xóa trong mặt nạ trong một JFormattedTextField

Tôi hiểu rằng nó sẽ thay thế ký tự không hợp lệ với một không gian, hoặc bất cứ điều gì bạn xác định qua setPlaceholderCharacter, nhưng những gì tôi cần nó để làm là cho phép xóa hoặc backspace, và KHÔNG chèn khoảng trắng vào vị trí của ký tự tôi đã xóa miễn là phần còn lại của chuỗi được cho phép trong mặt nạ. Ví dụ, với mặt nạ: *#*****, chuỗi "12 abc" là hợp lệ.
Nếu bạn đặt con trỏ giữa các ký tự b và c và nhấn nút backspace, tôi cần nó để xóa dấu b, dẫn đến "12 ac". Thay vào đó, nó xóa nó và thêm khoảng trắng, trở thành: "12 a c".

Ví dụ mã đơn giản bên dưới để minh họa.

Tôi sẽ đánh giá cao bất kỳ suy nghĩ hoặc ví dụ nào để giải quyết vấn đề này.


public class testFrame extends javax.swing.JFrame { 

    public testFrame() { 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     getContentPane().setLayout(new java.awt.FlowLayout()); 

     setMinimumSize(new Dimension(300,150)); 

     java.awt.Button closeButton = new java.awt.Button(); 
     JFormattedTextField maskTextField = new JFormattedTextField(); 
     maskTextField.setMinimumSize(new Dimension(100,30)); 

     getContentPane().add(maskTextField); 

     closeButton.setLabel("close"); 
     closeButton.addActionListener(new java.awt.event.ActionListener() { 
      public void actionPerformed(java.awt.event.ActionEvent evt) { 
       System.exit(0); 
      } 
     }); 

     getContentPane().add(closeButton); 

     try { 
      MaskFormatter someMask = new MaskFormatter("*#****"); 
      DefaultFormatterFactory formatterFactory 
       = new DefaultFormatterFactory(someMask); 
      maskTextField.setFormatterFactory(formatterFactory); 
     } catch (ParseException ex) { 
      ex.printStackTrace(); 
     } 
     maskTextField.setText("12 abc"); 

     pack(); 

    } 

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 

      public void run() { 
       new testFrame().setVisible(true); 
      } 
     }); 
    } 
} 

Đang cập nhật mã để phản ánh câu trả lời dưới đây. Tôi đã thêm một trường thứ hai để bạn có thể thấy hành vi có và không có bản sửa lỗi. Ngoài ra một sửa chữa nhỏ, tôi thay đổi kích thước các cửa sổ và tập trung nó vào màn hình để làm cho nó thân thiện hơn.

public class TestFrame kéo dài javax.swing.Jframe {

public testFrame() { 
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
    setMinimumSize(new java.awt.Dimension(300, 200)); 
    getContentPane().setLayout(new java.awt.FlowLayout()); 


    JFormattedTextField maskTextField = new JFormattedTextField(); 
    maskTextField.setMinimumSize(new Dimension(100,30)); 
    getContentPane().add(maskTextField); 


    JFormattedTextField maskTextField2 = new JFormattedTextField(); 
    maskTextField2.setMinimumSize(new Dimension(100,30)); 
    getContentPane().add(maskTextField2); 

    java.awt.Button closeButton = new java.awt.Button(); 
    closeButton.setLabel("close"); 
    closeButton.addActionListener(new java.awt.event.ActionListener() { 

     public void actionPerformed(java.awt.event.ActionEvent evt) { 
      System.exit(0); 
     } 
    }); 

    getContentPane().add(closeButton); 

    try { 

     MaskFormatter someMask = new MaskFormatter("*#****"); 
     DefaultFormatterFactory formatterFactory = 
      new DefaultFormatterFactory(someMask); 
     maskTextField.setFormatterFactory(formatterFactory); 

     MaskFormatter someMask2 = new MaskFormatter("*#****"); 
     DefaultFormatterFactory formatterFactory2 = 
      new DefaultFormatterFactory(someMask2); 
     maskTextField2.setFormatterFactory(formatterFactory2); 

    } catch (ParseException ex) { 
     ex.printStackTrace(); 
    } 

    maskTextField.setText("12 abc"); 
    maskTextField2.setText("12 abc"); 

    // added per suggestion below 
    if (maskTextField.getFormatter() instanceof DefaultFormatter) { 
     DefaultFormatter f = (DefaultFormatter) maskTextField.getFormatter(); 
     f.setAllowsInvalid(true); 

     // options are: 
     // JFormattedTextField.COMMIT 
     // JFormattedTextField.COMMIT_OR_REVERT --> default 
     // JFormattedTextField.REVERT 
     // JFormattedTextField.PERSIST 
     maskTextField.setFocusLostBehavior(JFormattedTextField.PERSIST); 
    } 
    pack(); 
    this.setLocationRelativeTo(null); 

} 

public static void main(String args[]) { 
    java.awt.EventQueue.invokeLater(new Runnable() { 

     public void run() { 
      new testFrame().setVisible(true); 
     } 
    }); 
} 

}

+0

âm thanh như một quan niệm sai lầm nhỏ: một mặt nạ là một cái gì đó với một lenght_ _fixed, mỗi vị trí điền hoặc bằng một ký tự hợp lệ hoặc một placeHolder. Khi xóa một char, nó được thay thế bởi placeHolder, trong ví dụ của bạn là mặc định là một khoảng trắng. Vì vậy, không gian đầu tiên là khác nhau từ thứ hai, ngữ nghĩa :-) Thay đổi placeHolder để cái gì khác, để thấy sự khác biệt đó.Khi yêu cầu của bạn có vẻ giống như bất kỳ thứ gì-char-up-to-a-max-of-4-sau-chữ số, bạn sẽ phải triển khai trình định dạng tùy chỉnh như @DuncanJones đã đề xuất – kleopatra

+0

Tôi không quan tâm nó là chiều dài cố định, và tôi đoán tôi chỉ có một trường hợp sử dụng đặc biệt mà họ không phục vụ cho. Ví dụ: nếu mặt nạ của bạn là (###) ### - ### và bạn đang cố gắng nhập (123) 456-7890 và vô tình nhập vào hai 2 giây, nghĩa là (122) 345-6789, mặt nạ chuẩn hành vi dường như có nghĩa là nếu bạn xóa 2 đầu tiên, nó sẽ thay thế một không gian (trình giữ chỗ) cho bạn (12) 345-6789. Tôi cần nó để xóa ký tự và thêm phần giữ chỗ ở cuối chuỗi thay thế. Nhưng tôi đoán đây không phải là thứ mà người khác cần vì vậy tôi sẽ phải tạo một bộ định dạng tùy chỉnh: ( –

+0

ahh ... Tôi hiểu, cảm ơn vì đã làm rõ số – kleopatra

Trả lời

5

Trước hết, cảm ơn bạn đã đăng một tấm gương làm việc đàng hoàng.

Dường như DefaultFormatter là trình định dạng được sử dụng bởi trường văn bản được che dấu của bạn. Tôi nhận thấy rằng tôi có thể cho phép chỉnh sửa không hợp lệ tạm thời theo cách sau:

if (maskTextField.getFormatter() instanceof DefaultFormatter) { 
    DefaultFormatter f = (DefaultFormatter) maskTextField.getFormatter(); 
    f.setAllowsInvalid(true);   
} 

Hy vọng rằng đủ con trỏ để giúp bạn bắt đầu. Mặc dù lưu ý rằng bản sửa lỗi nhanh này có hành vi thú vị là xóa hoàn toàn nội dung của trường văn bản nếu bạn thay đổi tiêu điểm trong khi giá trị không hợp lệ nằm trong trường. Điều này có vẻ trái với JavaDoc cho JFormattedTextField cho thấy hành vi mặc định là COMMIT_OR_REVERT.

+0

Tôi nghĩ đây chắc chắn là một gợi ý tuyệt vời. bạn đặt trong maskTextField.setFocusLostBehavior (JFormattedTextField.PERSIST), nó dường như làm cho nó không rõ ràng kết quả.Cảm ơn bạn! –

+0

thử nghiệm một số chi tiết, tôi nhận ra điều này không thực sự giải quyết vấn đề. Thêm setAllowsInvalid (true) làm cho nó bỏ qua mặt nạ, Điều tôi mong đợi là NẾU hành động xóa không làm mất hiệu lực mặt nạ (bằng cách dịch chuyển ký tự ở bên phải của các ký tự đã xóa) thì việc xóa hoặc quay lại chỉ cần thực hiện điều đó và không thêm Tôi đoán nếu hành động xóa không làm mất hiệu lực mặt nạ, thì nó sẽ không hoạt động –

+1

Nếu mặt nạ có chiều dài cố định (có lẽ là hầu hết/tất cả đều là?), thì sẽ không xóa * luôn luôn * làm mất hiệu lực mặt nạ? Hoặc bạn tạm thời cho phép phá vỡ các quy tắc mặt nạ, hoặc bạn sẽ luôn luôn kết thúc với hành vi không gian lẻ này. Có lẽ bạn có thể xem xét việc viết lớp con của riêng bạn của 'AbstractFormatter'? –

1

Chỉ cần suy nghĩ - chắc chắn là không phù hợp cho sản xuất và có thể không nhất thiết trong trường hợp chung: bạn có thể thử bọc tài liệu mặc địnhFilter và gọi kiểm tra/thao tác tùy chỉnh trước/sau khi gọi đại biểu.

Dưới đây là một đoạn mà dường như làm việc cho các ví dụ cụ thể trong câu hỏi của bạn:

public static class MyMaskFormatter extends MaskFormatter { 

    DocumentFilter filter; 

    /** 
    * @param string 
    * @throws ParseException 
    */ 
    public MyMaskFormatter(String string) throws ParseException { 
     super(string); 
    } 

    @Override 
    protected DocumentFilter getDocumentFilter() { 
     if (filter == null) { 
      filter = new MyDocumentFilter(super.getDocumentFilter()); 
     } 
     return filter; 
    } 

    public class MyDocumentFilter extends DocumentFilter { 

     DocumentFilter delegate; 

     MyDocumentFilter(DocumentFilter delegate) { 
      this.delegate = delegate; 
     } 

     @Override 
     public void remove(FilterBypass fb, int offset, int length) 
       throws BadLocationException { 
      String toRemove = fb.getDocument().getText(offset, length); 
      delegate.remove(fb, offset, length); 
      String replaced = fb.getDocument().getText(offset, length); 
      if (replaced.charAt(0) == getPlaceholderCharacter() && 
       toRemove.charAt(0) != getPlaceholderCharacter() ) { 
       int sublength = fb.getDocument().getLength() - offset; 
       String text = fb.getDocument().getText(offset, sublength); 
       text = text.substring(1) + text.charAt(0); 
       replace(fb, offset, sublength, text, null); 
       getFormattedTextField().setCaretPosition(offset); 
       //getNavigationFilter().setDot(fb, offset, null); 
      } 
     } 

     @Override 
     public void insertString(FilterBypass fb, int offset, 
       String string, AttributeSet attr) 
       throws BadLocationException { 
      delegate.insertString(fb, offset, string, attr); 
     } 

     @Override 
     public void replace(FilterBypass fb, int offset, int length, 
       String text, AttributeSet attrs) 
       throws BadLocationException { 
      delegate.replace(fb, offset, length, text, attrs); 
     } 

    } 

}