2012-06-15 41 views
6

Tôi đang cố tạo một JFormattedTextField chỉ chấp nhận thời gian 24 giờ.Thời gian 24 giờ nghiêm ngặt trong JFormattedTextField

Tôi rất gần với giải pháp, nhưng có một trường hợp trong đó ví dụ mã sau không hoạt động.

Nếu bạn nhập thời gian "222" và thay đổi tiêu điểm từ trường, thời gian được sửa thành "2202". Tôi muốn nó chỉ chấp nhận đầy đủ 4 chữ số 24 giờ. Mã này hoạt động như tôi muốn trong hầu hết các trường hợp, ngoại trừ mã mà tôi vừa đề cập. Bất kỳ đề xuất?

public static void main(String[] args) throws ParseException { 
     DateFormat dateFormat = new SimpleDateFormat("HHmm"); 
     dateFormat.setLenient(false); 

     DateFormatter dateFormatter = new DateFormatter(dateFormat); 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JFormattedTextField textField = new JFormattedTextField(dateFormatter); 
     frame.add(textField, BorderLayout.NORTH); 

     frame.add(new JTextField("This is here so you can change focus."), BorderLayout.SOUTH); 
     frame.setSize(250, 100); 
     frame.setVisible(true); 
    } 
+0

Cách giải quyết đơn giản là việc sử dụng của 'JTextField', và sử dụng' DocumentFilter' :-) Đối với [DocumentFilter] (http://docs.oracle.com/javase/7/docs/api/javax/swing/text/DocumentFilter.html) bạn có thể kiểm tra [ví dụ] này (http://stackoverflow.com/questions/9477354/how-to-allow -introducing-only-digits-in-jtextfield/9478124 # 9478124) –

+0

không đúng, có thể là 02:22 hoặc 22:02 – mKorbel

+4

Bạn có thể không may mắn nếu bạn đang sử dụng SimpleDateFormat. Từ Javadoc: "Để phân tích cú pháp, số chữ hoa văn bị bỏ qua trừ khi cần phải tách hai trường liền kề." Nó phân tích hai chữ số đầu tiên thành trường giờ, do đó, nó biết rằng số còn lại phải là trường phút. – Alex

Trả lời

5

Như những người khác đã đề cập, đặt cược tốt nhất của bạn có lẽ là để xác nhận độ dài của chuỗi đầu vào. phương pháp ưa thích của tôi sẽ là subclassing SimpleDateFormat để giữ tất cả các logic phân tích ở một nơi:

public class LengthCheckingDateFormat extends SimpleDateFormat { 

    public LengthCheckingDateFormat(String pattern) { super(pattern); } 

    @Override 
    public Date parse(String s, ParsePosition p) { 
    if (s == null || (s.length() - p.getIndex()) < toPattern().length()) { 
     p.setErrorIndex(p.getIndex()); 
     return null; 
    } 
    return super.parse(s, p); 
    } 
} 
+0

Hoặc thậm chí có thể sử dụng lại nhiều hơn: tạo trang trí cho định dạng Java chuẩn chỉ cho phép phân tích cú pháp thành công khi toàn bộ chuỗi đầu vào có thể được phân tích cú pháp ('ParseAllFormat'), vì vậy nó có thể được sử dụng lại – Robin

+1

Câu trả lời hay, tôi thích ghi đè SimpleDateFormat hơn là thêm người nghe tập trung. Một thay đổi mà tôi đã thực hiện cho mã của bạn thay vì ném một ParseException, tôi trả về null theo phương thức phân tích cú pháp SimpleDateFormat JavaDoc. – FuryComputers

+0

@Robin điểm tốt, điều này có thể có thể được thay đổi để bọc một trình định dạng chung để thực hiện việc kiểm tra tương tự. – Alex

2

Tôi tự hỏi từ khi DateFormatter xuất hiện để thực hiện 'gần như' tất cả mẹo.

Vì vậy, tại sao bạn không ghi đè phương thức của phương pháp xác thực và định dạng cuối cùng để xử lý tất cả các nhập String s quá ngắn như trống String.

 DateFormatter dateFormatter = new DateFormatter(dateFormat) { 
      @Override 
      public Object stringToValue(String text) throws ParseException { 
       if(!getFormattedTextField().hasFocus()) 
        if (text.length() != 4) { 
         return null; 
        } 
       return super.stringToValue(text); 
      }    
     }; 

EDIT:

Theo đề nghị của @nIcE bò dễ nhất sẽ được để phục vụ nó trên tập trung mất:

final JFormattedTextField textField = new JFormattedTextField(dateFormatter); 
    textField.addFocusListener(new FocusAdapter() { 
     @Override 
     public void focusLost(FocusEvent e) { 
      super.focusLost(e); 
      if(textField.getText().length() != 4) 
       textField.setText(""); 
     } 
    }); 
+0

Tôi sẽ nói cách tiếp cận này có thể đứng thử nghiệm của thời gian :-) –

+0

@ nIcEcOw Tôi sẽ nói điều này dẫn đến hành vi bất ngờ của 'JFormattedTextField'. Thông thường khi giá trị không hợp lệ, nó sẽ trở về giá trị hợp lệ trước đó trên 'focusLost'. Nhưng ở đây bạn đang tự sửa đổi nội dung .... Và không chắc chắn điều gì sẽ xảy ra khi bạn nhấn ENTER với giá trị không hợp lệ. Vì vậy, tôi mạnh mẽ sẽ đề nghị để đi cho câu trả lời chấp nhận được đăng bởi Alex – Robin

+0

@Robin ENTER không làm bất cứ điều gì theo mặc định. BTW: Tôi đã tìm ra phương thức 'DateFormatter' có định dạng mà tôi thêm vào một giải pháp liên quan đến câu trả lời của tôi, đáng buồn là nó cũng chuyển tiếp trên tiêu điểm của trường text vì tôi không biết cách phát hiện đúng thời điểm để gọi kiểm tra độ dài như phương thức 'stringToValue' được gọi trên bất kỳ khóa nhập nào. Đặt tất cả cùng nhau tôi sẽ đi với câu trả lời của Alex bản thân mình (1) vì nó ít hacky. – Boro

Các vấn đề liên quan