JFormattedTextField: valor de duração do tempo de input

Eu quero usar um JFormattedTextField para permitir que o usuário insira valores de duração de tempo em um formulário. Os valores válidos da amostra são:

2h 30m
72h 15m
6h
0h

No entanto, estou tendo sucesso limitado com isso. Alguém pode sugerir como isso pode ser feito? Eu estou bem se este resultado pode ser alcançado usando um JTextField também.

Obrigado!


Se valer alguma coisa, aqui está minha tentativa atual:

  mFormattedText.setFormatterFactory( new DefaultFormatterFactory( new DateFormatter( new SimpleDateFormat("H mm")))); 

Esta sorta funciona, exceto que:

  • Eu não consigo que h m aparecer como texto simples (tentei escaping) *
  • O número de horas tem um máximo

*: Veja a resposta de @ nanda

O código:

 public static void main(String[] args) { JFrame jFrame = new JFrame(); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setLayout(new BorderLayout()); jFrame.setPreferredSize(new Dimension(500, 500)); final JFormattedTextField comp = new JFormattedTextField(); comp.setFormatterFactory(new DefaultFormatterFactory(new DateFormatter(new SimpleDateFormat( "H'h' mm'm'")))); comp.setValue(Calendar.getInstance().getTime()); comp.addPropertyChangeListener("value", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { System.out.println(comp.getValue()); } }); jFrame.getContentPane().add(comp, BorderLayout.CENTER); jFrame.pack(); jFrame.setVisible(true); } 

Aqui está um exemplo do uso de InputVerifier para acomodar vários formatos de input.

 import java.awt.EventQueue; import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.swing.Box; import javax.swing.InputVerifier; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.text.DateFormatter; import javax.swing.text.DefaultFormatterFactory; public class FormattedFields { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { //@Override public void run() { new FormattedFields(); } }); } FormattedFields() { Box form = Box.createVerticalBox(); form.add(new JLabel("Date & Time:")); DateTimeField dtField = new DateTimeField(new Date()); form.add(dtField); form.add(new JLabel("Amount:")); JFormattedTextField amtField = new JFormattedTextField( NumberFormat.getCurrencyInstance()); amtField.setValue(100000); form.add(amtField); JFrame frame = new JFrame(); frame.add(form); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } class DateTimeField extends JFormattedTextField { public DateTimeField() { super(DateTimeVerifier.getDefaultFormat()); this.setInputVerifier(new DateTimeVerifier(this)); } public DateTimeField(Date date) { this(); this.setValue(date); } @Override protected void invalidEdit() { if (!this.getInputVerifier().verify(this)) { super.invalidEdit(); } } } class DateTimeVerifier extends InputVerifier { private static List validForms = new ArrayList(); static { validForms.add(new SimpleDateFormat("dd-MMM-yyyy HH'h':mm'm'")); validForms.add(new SimpleDateFormat("dd-MMM-yyyy HH:mm")); } private JFormattedTextField tf; private Date date; public DateTimeVerifier(JFormattedTextField tf) { this.tf = tf; } @Override public boolean verify(JComponent input) { boolean result = false; if (input == tf) { String text = tf.getText(); for (SimpleDateFormat format : validForms) { try { date = format.parse(text); result |= true; } catch (ParseException pe) { result |= false; } } } return result; } @Override public boolean shouldYieldFocus(JComponent input) { if (verify(input)) { tf.setValue(date); return true; } else { return false; } } public static SimpleDateFormat getDefaultFormat() { return validForms.get(0); } } 

Você já tentou H'h' mm'm' ?

hmm, o que eu acho é que você pode alcançar o mesmo objective, criando três JTextField diferentes para todos os três componentes de tempo, um para a HORA, MINUTO e Segundo (se estiver incluído) para obter sua opinião … apenas um pensamento, você poderia apenas concatená-los se for necessário … apenas um pensamento …

tl; dr

 Duration.parse( "PT2H30M" ) 

ISO 8601

Se você estiver disposto a redefinir seus formatos de input desejados, sugiro usar os formatos já existentes definidos pela norma ISO 8601 .

O padrão PnYnMnDTnHnMnS usa um P para marcar o início, um T para separar qualquer porção de anos-meses-dias de qualquer parte de horas-minutos-segundos.

Uma hora e meia é a PT1H30M , por exemplo.

java.time

As classs java.time usam os formatos ISO 8601 por padrão ao analisar / gerar cadeias. Isso inclui as classs Period e Duration para representar períodos de tempo não anexados à linha do tempo.

 Duration d = Duration.ofHours( 1 ).plusMinutes( 30 ); String output = d.toString(); 

Indo na outra direção, analisando uma string.

 Duration d = Duration.parse( "PT1H30M" ); 

Veja o código ao vivo em IdeOne.com .

Veja o meu semelhante Resposta a uma pergunta semelhante .


Sobre o java.time

O framework java.time está embutido no Java 8 e posterior. Essas classs substituem as antigas classs herdadas de data e hora legadas , como java.util.Date , Calendar e SimpleDateFormat .

O projeto Joda-Time , agora em modo de manutenção , aconselha a migration para as classs java.time .

Para saber mais, veja o Oracle Tutorial . E pesquise o Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Onde obter as classs java.time?

  • Java SE 8 e SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação integrada.
    • O Java 9 adiciona alguns resources e correções menores.
  • Java SE 6 e SE 7
    • Grande parte da funcionalidade java.time é transferida para o Java 6 e 7 no ThreeTen-Backport .
  • Android
    • O projeto ThreeTenABP adapta o ThreeTen-Backport (mencionado acima) especificamente para o Android.
    • Veja Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende java.time com classs adicionais. Este projeto é um campo de testes para possíveis futuras adições ao java.time. Você pode encontrar algumas classs úteis aqui como Interval , YearWeek , YearQuarter e muito mais .