JFormattedTextField: значение длительности ввода времени

Я хочу использовать JFormattedTextField, чтобы пользователь мог вводить значения времени duration в форму. Примеры допустимых значений:

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

Однако я имею ограниченный успех с этим. Может ли кто-нибудь предложить, как это можно сделать? Я согласен, если этого результата можно добиться и с помощью JTextField.

Спасибо!


Если это чего-то стоит, вот моя текущая попытка:

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

Этот вид работает, за исключением того, что:

  • Я не могу сделать так, чтобы h и m отображались как обычный текст (я пытался экранировать) *
  • Максимальное количество часов

*: см. ответ @nanda


person bguiz    schedule 10.02.2010    source источник


Ответы (5)


Код:

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);
}
person nanda    schedule 11.02.2010

Вот пример использования InputVerifier для размещения несколько форматов ввода.

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<SimpleDateFormat> validForms =
        new ArrayList<SimpleDateFormat>();


    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);
    }
}
person trashgod    schedule 11.02.2010

Вы пробовали H'h' mm'm'?

person nanda    schedule 10.02.2010
comment
@nanda, спасибо, что указали, как экранировать символы (сработало), но что не сработало, так это то, что я хочу, чтобы пользователи вводили 6h 42m, а это приводит к Unparseable date: "6h 42m", поэтому я все еще застрял. Это работает только тогда, когда пользователь вводит что-то вроде 6:42:00 AM, что не работает для меня, поскольку цель состоит в том, чтобы ввести продолжительность времени. - person bguiz; 11.02.2010
comment
@trashgod, не могли бы вы подсказать, как использовать InputVerifier в этом сценарии? - person bguiz; 11.02.2010
comment
Это странно... может быть, вам следует поделиться своим полным кодом, потому что он работает с моим кодом (см. другой ответ, чтобы увидеть полный код) - person nanda; 11.02.2010

хм, я думаю, что вы можете достичь той же цели, создав три разных JTextField для всех трех компонентов времени, один для ЧАСА, МИНУТЫ и секунды (если он включен), чтобы получить ваш ввод... просто мысль, вы можете просто объединить их, если вам это необходимо... просто мысль...

person ultrajohn    schedule 10.02.2010
comment
@ultrajohn, спасибо за ваш вклад, но это часть требований, чтобы он был в одном поле и чтобы формат был таким, как я описал в вопросе. - person bguiz; 10.02.2010

tl;dr

Duration.parse( "PT2H30M" )

ИСО 8601

Если вы хотите переопределить желаемые форматы ввода, я предлагаю использовать уже существующие форматы, определенные ISO 8601. стандарт.

Шаблон PnYnMnDTnHnMnS использует P для обозначения начала, T для отделения любой части лет-месяцев-дней от любой части часов-минут-секунд.

Например, полтора часа — это PT1H30M.

Java.время

Классы java.time по умолчанию используют форматы ISO 8601 при разборе/генерации строк. Это включает в себя Period и Duration для представления промежутков времени, не привязанных к Лента новостей.

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

Идем в другом направлении, анализируя строку.

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

См. действующий код на сайте IdeOne.com.

См. мой аналогичный ответ на аналогичный вопрос.


О java.time

Платформа java.time встроен в Java 8 и более поздние версии. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и SimpleDateFormat.

Проект Joda-Time, теперь в режим обслуживания, советует перейти на java.time.

Чтобы узнать больше, см. учебник по Oracle. И поищите множество примеров и пояснений в Stack Overflow. Спецификация: JSR 310.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных дополнений к java.time в будущем. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и подробнее.

person Basil Bourque    schedule 30.12.2016