2012-06-15 21 views
6

Sto provando a creare un JFormattedTextField che accetta solo un orario di 24 ore.Tempo di 24 ore rigoroso in JFormattedTextField

Sono molto vicino a una soluzione, ma ho un caso in cui il seguente esempio di codice non funziona.

Se si immette l'ora "222" e si cambia messa a fuoco dal campo, l'ora viene corretta su "2202". Mi piacerebbe che accetti solo un tempo di 24 ore a 4 cifre. Questo codice funziona come voglio in quasi tutti i casi, tranne quello che ho appena menzionato. Eventuali suggerimenti?

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

La soluzione più semplice è l'uso di 'JTextField', e l'utilizzo di' DocumentFilter' :-) Per [DocumentFilter] (http://docs.oracle.com/javase/7/docs/api/javax/swing/text/DocumentFilter.html) puoi controllare questo [esempio] (http://stackoverflow.com/questions/9477354/how-to-allow -introdurre-only-digit-in-jtextfield/9478124 # 9478124) –

+0

non vero, potrebbe essere 02:22 o 22:02 – mKorbel

+4

Potrebbe essere sfortunato se si utilizza SimpleDateFormat. Da Javadoc: "Per l'analisi, il numero di lettere di pattern viene ignorato a meno che non sia necessario separare due campi adiacenti." Analizza le prime due cifre come il campo delle ore, quindi sa che la cifra rimanente deve essere il campo dei minuti. – Alex

risposta

5

Come altri hanno già detto, la cosa migliore è probabilmente quello di convalidare la lunghezza della stringa di input. Il mio approccio preferito sarebbe sottoclasse SimpleDateFormat per mantenere tutta la logica di analisi in un unico luogo:

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

O ancora più riutilizzabile: creare un decoratore per un formato Java standard che indica solo l'analisi è utile quando l'intera stringa di input può essere analizzata (un 'ParseAllFormat'), quindi può essere riutilizzata – Robin

+1

Ottima risposta, mi piace sovrascrivere SimpleDateFormat piuttosto che aggiungendo l'ascoltatore di messa a fuoco. L'unica modifica che ho apportato al tuo codice è piuttosto che lanciare una ParseException, restituisco null secondo il metodo di analisi SimpleDateFormat JavaDoc. – FuryComputers

+0

@Robin good point, questo potrebbe probabilmente essere cambiato per avvolgere un formattatore generale per fare lo stesso controllo. – Alex

2

mi chiedo quanto il DateFormatter sembra fare 'quasi' tutto il trucco.

Pertanto, perché non si sostituisce al metodo uno che esegue la convalida finale e la formattazione per trattare tutti gli String s immessi che sono troppo brevi come vuoti 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:

Come suggerito dal @nIcE mucca il più facile sarà quello di servire a fuoco perse:

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

Dirò che questo approccio può resistere alla prova del tempo :-) –

+0

@nIcEcOw Direi che questo porta a un comportamento inaspettato del 'JFormattedTextField'. Normalmente quando il valore non è valido ritorna al valore valido precedente su 'focusLost'. Ma qui stai modificando manualmente i contenuti .... E non sono sicuro di cosa succederà quando si preme INVIO con un valore non valido. Quindi suggerirei vivamente di andare per la risposta accettata inviata da Alex – Robin

+0

@Robin ENTER non fa nulla per impostazione predefinita. BTW: Ho trovato il metodo di 'DateFormatter' che fa il formato ho aggiunto una soluzione che lo coinvolge alla mia risposta, purtroppo si relaziona anche sul focus del campo di testo in quanto non ero sicuro di come individuare il momento giusto per chiamare il test di lunghezza dato che il metodo 'stringToValue' viene chiamato su qualsiasi tasto di invio. Mettendo tutto insieme vorrei andare con la risposta di Alex me stesso (+1) in quanto è meno hacky. – Boro

Problemi correlati