Как отформатировать текстовое поле javafx

Я хотел бы иметь возможность вводить время в текстовом поле javafx в формате чч: мм: сс. Как мне отформатировать текстовое поле? У меня уже есть метод регулярного выражения, поэтому он принимает только числа в качестве входных данных:

public void format(TextField t, String regex){
    TextFormatter<String> formatter = new TextFormatter<String>( change -> {
        change.setText(change.getText().replaceAll(regex, ""));
        return change; 


    });
    t.setTextFormatter(formatter);
}

и у меня также есть метод, который ограничивает количество символов, разрешенных в текстовом поле:

public void limitLength(int maxLength, TextField t){
    t.lengthProperty().addListener(new ChangeListener<Number>() {

        @Override
        public void changed(ObservableValue<? extends Number> observable,
                Number oldValue, Number newValue) {
            if (newValue.intValue() > oldValue.intValue()) {
                // Check if the new character is greater than LIMIT
                if (t.getText().length() >= maxLength) {

                    t.setText(t.getText().substring(0, maxLength));
                }
            }
        }
    });
}

Однако ничто из этого не помогает мне получить нужный формат времени. В идеале исходный текст должен быть 00:00:00, а пользователь ТОЛЬКО может редактировать цифры, не касаясь двоеточий. Также было бы здорово, если бы я мог убедиться, что между каждым двоеточием есть 2 цифры, т.е. пользователь не должен перемещаться между цифрами, например, 0:000:00.

Спасибо за любую помощь.


person Cornelius    schedule 10.02.2016    source источник
comment
См. stackoverflow.com/questions/ 32613619/   -  person James_D    schedule 10.02.2016


Ответы (3)


Использование SimpleDateFormat

Уже существует класс, предназначенный для форматирования дат, который можно использовать с TextField textFormatter: SimpleDateFormat

TextField tf = new TextField();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
tf.setTextFormatter(new TextFormatter<>(new DateTimeStringConverter(format), format.parse("00:00:00")));

Подробнее см. в javadoc для SimpleDateFormat. описание значения символов.

Использование 3 разных текстовых полей

Вы также можете использовать 3 разных TextField, удалить фон и границу и поместить их в HBox, чтобы получить нередактируемые ::

TextField hours = new TextField();
TextField minutes = new TextField();
TextField seconds = new TextField();
StringConverter<Integer> minSecConverter = new IntRangeStringConverter(0, 59);
minutes.setTextFormatter(new TextFormatter<>(minSecConverter, 0));
seconds.setTextFormatter(new TextFormatter<>(minSecConverter, 0));
hours.setTextFormatter(new TextFormatter<>(new IntRangeStringConverter(0, 23), 0));
prepareTextField(hours);
prepareTextField(minutes);
prepareTextField(seconds);
    
HBox fields = new HBox(hours, createLabel(),minutes, createLabel(), seconds);
fields.setPadding(new Insets(4));
fields.setStyle("-fx-background-color: white;");
public static void prepareTextField(TextField tf) {
    tf.setAlignment(Pos.CENTER);
    tf.setBackground(Background.EMPTY);
    tf.setBorder(Border.EMPTY);
    tf.setPadding(Insets.EMPTY);
    tf.setPrefColumnCount(2);
}

public static class IntRangeStringConverter extends StringConverter<Integer> {

    private final int min;
    private final int max;

    public IntRangeStringConverter(int min, int max) {
        this.min = min;
        this.max = max;
    }
    
    @Override
    public String toString(Integer object) {
        return String.format("%02d", object);
    }

    @Override
    public Integer fromString(String string) {
        int integer = Integer.parseInt(string);
        if (integer > max || integer < min) {
            throw new IllegalArgumentException();
        }

        return integer;
    }

}

public static Label createLabel() {
    Label label = new Label(":");
    label.setPrefWidth(3);
    return label;
}
person fabian    schedule 10.02.2016

Я использую этот простой класс до тех пор, пока не станет доступен TimePicker, соответствующий DatePicker. Стратегия здесь состоит в том, чтобы проверять запись, когда поле теряет фокус. Если он не соответствует регулярному выражению (с необязательными секундами и необязательными AM, PM, am, pm), он привлекает внимание пользователя звуковым сигналом, заменой записи на правильно отформатированную, запросом фокуса и выделением записи. Я делаю validate() общедоступной, чтобы контейнер (например, диалоговое окно) также мог проверять правильность перед закрытием (например, в случае потери фокуса нажатием кнопки OK):

public class TimeTextField extends TextField 
{   
    public TimeTextField(String init) {
        super(init) ;
        focusedProperty().addListener((o, oldV, newV) -> changed(newV));
    }

    public TimeTextField() {
        this("12:00 PM");
    }

    private void changed(boolean focus) {
        if (!focus) {
            if (!validate()) { 
                setText("12:00 PM");
                selectAll();
                requestFocus();
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }

    public boolean validate()  {
        return getText()
        .matches("(0?[1-9]|1[0-2]):[0-5][0-9](:[0-5][0-9])? ?[APap][mM]$");
    }    
}
person Paul    schedule 07.01.2017

Вы должны вставить ':' самостоятельно. Потому что таким образом пользователю разрешено только вставлять числа. После каждых двух чисел вы вставляете ':' внутри прослушивателя изменений. Дополнительно легко вставить время.

person kayf    schedule 10.02.2016
comment
что, если пользователь удалит ':', тогда он не сможет добавить его снова. - person Cornelius; 10.02.2016
comment
да ты прав. ':' также должен быть возможен. Я написал прослушиватель chaneg для входных IP-адресов, и есть '.' допустимый. - person kayf; 11.02.2016