2012-06-15 8 views
6

Próbuję utworzyć JFormattedTextField, który akceptuje tylko 24-godzinny czas.Ścisły 24-godzinny czas w JFormattedTextField

Jestem bardzo blisko rozwiązania, ale mam jeden przypadek, w którym poniższy przykład kodu nie działa.

Po wprowadzeniu czasu "222" i zmianie ostrości z pola, czas jest korygowany na "2202". Chciałbym, aby zaakceptował tylko 4-cyfrowy 24-godzinny czas. Ten kod działa tak, jak chcę w prawie wszystkich przypadkach, z wyjątkiem tego, o którym wspomniałem. Jakieś sugestie?

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

Łatwy Rozwiązaniem jest użycie 'JTextField' i używając' DocumentFilter' :-) Dla [DocumentFilter] (http://docs.oracle.com/javase/7/docs/api/javax/swing/text/DocumentFilter.html) możesz sprawdzić ten [przykład] (http://stackoverflow.com/questions/9477354/how-to-allow -instrukcja-tylko-cyfr-w-jtextfield/9478124 # 9478124) –

+0

nieprawda, może być 02:22 lub 22:02 – mKorbel

+4

Możesz mieć dużo szczęścia, jeśli używasz SimpleDateFormat. Z Javadoc: "Podczas analizowania liczba liter wzorcowych jest ignorowana, chyba że trzeba oddzielić dwa sąsiednie pola." Parsuje pierwsze dwie cyfry jako pole godziny, więc wie, że pozostała cyfra musi być polem minut. – Alex

Odpowiedz

5

Jak wspominają inni, najlepiej jest zapewne sprawdź długość łańcucha wejściowego. Moje preferowane podejście byłoby instacji SimpleDateFormat aby wszystkie logikę parsowania w jednym miejscu:

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

Lub jeszcze więcej do wielokrotnego użytku: stwórz dekorator dla standardowego formatu Java, który tylko wskazuje, że parsowanie powiodło się, gdy cały łańcuch wejściowy mógł zostać przeanalizowany ('ParseAllFormat'), więc może być ponownie użyty – Robin

+1

Świetna odpowiedź, lubię przesłonić SimpleDateFormat zamiast dodanie detektora skupienia. Jedną zmianą wprowadzoną w twoim kodzie jest raczej niż wyrzucenie wyjątku ParseException, zwracam wartość null zgodnie z metodą parowania SimpleDateFormat JavaDoc. – FuryComputers

+0

@Robin dobry punkt, to prawdopodobnie można zmienić na owinąć ogólny formatter, aby zrobić to samo sprawdzanie. – Alex

2

zastanawiam skoro DateFormatter wydaje się zrobić „prawie” wszystko załatwi.

Dlatego nie należy nadpisywać tej metody, która powoduje, że ostateczna walidacja i formatowanie wszystkich wprowadzonych String s są zbyt krótkie jako puste 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:

Jak sugeruje @nIcE krowa najłatwiej będzie służyć na naciskiem przegrane:

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

Powiem, że to podejście może wytrzymać próbę czasu :-) –

+0

@nIcEcOw Powiedziałbym, że prowadzi to do nieoczekiwanego zachowania 'JFormattedTextField'. Zwykle, gdy wartość jest nieprawidłowa, powraca do poprzedniej, poprawnej wartości na 'focusLost'. Ale tutaj ręcznie modyfikujesz zawartość .... I nie wiesz, co się stanie, gdy naciśniesz ENTER z nieprawidłową wartością. Więc zdecydowanie sugeruję, aby przejść do zaakceptowanej odpowiedzi wysłanej przez Alex – Robin

+0

@Robin ENTER nie robi nic domyślnie. BTW: Znalazłem metodę 'DateFormatter', która ma format, do którego dodałem rozwiązanie z jej udziałem, ale niestety jest również skupiona na polu tekstowym, ponieważ nie byłem pewien, jak wykryć odpowiedni czas na wywołanie test długości, ponieważ metoda 'stringToValue' jest wywoływana przy każdym naciśnięciu klawisza. Łącząc to wszystko, sam odpowiedziałbym z odpowiedzią Alexa (+1), ponieważ jest mniej odrażający. – Boro

Powiązane problemy