В Java, как я могу объединить LocalDate и строку в формате времени в одно наблюдаемое свойство LocalDateTime? - PullRequest
0 голосов
/ 04 ноября 2019

Моя попытка объединить значения DatePicker (который обрабатывает выбор даты, но не времени) и TextField (который обрабатывает время) в наблюдаемом LocalDateTime обоих соединенных.

Я установил наблюдаемые свойства для обоих в модели, но у меня возникают трудности с их соединением.

Пока мне удалось сделать несколько попыток с Bindings.createObjectBinding(), но я не могуКажется, у меня там большой успех.

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

1 Ответ

1 голос
/ 04 ноября 2019

Используя LocalDateTime#of(LocalDate,LocalTime), вы можете создать LocalDateTime из LocalDate и LocalTime. Теперь вам нужен способ получить экземпляр как LocalDate, так и LocalTime. К счастью, элемент управления DatePicker дает вам его значение как LocalDate, так что мы закончили. Далее мы находим способ получить LocalTime от TextField. Это возможно с помощью TextFormatter и StringConverter, которые знают, как преобразовать String в LocalTime и наоборот. Для этого варианта использования есть встроенный StringConverter: LocalTimeStringConverter.

Как только у нас есть и DatePicker, и TextFormatter, нам нужно создать привязку, которая создаетLocalDateTime из двух значений. Поскольку и DatePicker, и TextFormatter имеют свойство value, которое содержит LocalDate и, в этом случае, LocalTime, соответственно, создание привязки относительно просто с Bindings#createObjectBinding(Callable,Observable...).

DatePicker dp = new DatePicker();
// Have to associate the TextFormatter with a TextField
TextFormatter<LocalTime> tf = new TextFormatter<>(new LocalTimeStringConverter());

ObjectBinding<LocalDateTime> binding = Bindings.createObjectBinding(() -> {
    LocalDate ld = dp.getValue();
    LocalTime lt = tf.getValue();
    return ld == null || lt == null ? null : LocalDateTime.of(ld, lt);
}, dp.valueProperty(), tf.valueProperty());

Вот полный пример:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.converter.LocalTimeStringConverter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class App extends Application {

  @Override
  public void start(Stage primaryStage) {
    DatePicker datePicker = new DatePicker();
    datePicker.setValue(LocalDate.now());

    TextField timeField = new TextField();
    TextFormatter<LocalTime> timeFieldFormatter =
        new TextFormatter<>(new LocalTimeStringConverter());
    timeField.setTextFormatter(timeFieldFormatter);
    timeFieldFormatter.setValue(LocalTime.now());

    HBox dateTimeBox = new HBox(10, datePicker, timeField);
    dateTimeBox.setAlignment(Pos.CENTER);

    ObjectBinding<LocalDateTime> ldtBinding = Bindings.createObjectBinding(() -> {
      LocalDate date = datePicker.getValue();
      LocalTime time = timeFieldFormatter.getValue();
      return date == null || time == null ? null : LocalDateTime.of(date, time);
    }, datePicker.valueProperty(), timeFieldFormatter.valueProperty());

    Label ldtLabel = new Label();
    ldtLabel.textProperty().bind(Bindings.createStringBinding(() -> {
      LocalDateTime dateTime = ldtBinding.get();
      return dateTime == null ? null : dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }, ldtBinding));

    VBox root = new VBox(15, dateTimeBox, ldtLabel);
    root.setAlignment(Pos.CENTER);
    root.setPadding(new Insets(25));

    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }
}

Вышеприведенное связывает текст Label с ObjectBinding<LocalDateTime>. Значение TextFormatter будет обновляться всякий раз, когда текст «зафиксирован» (например, при нажатии , введите , когда TextField имеет фокус).

То, как я сконструировал LocalTimeStringConverter, означает, что он будет использовать мои Locale и FormatStyle.SHORT для анализа и форматирования LocalTime. Например, для меня это означает что-то вроде 3:30 PM или 11:25 AM. Это настраивается - см. Различные конструкторы LocalTimeStringConverter.

...