【问题标题】:Is there any Date and Time picker available for javaFx?javaFx 是否有可用的日期和时间选择器?
【发布时间】:2015-04-14 02:40:03
【问题描述】:

我是 Java 新手,我已经开始使用 javaFx 在 Java 中开发应用程序。搜索了很多,但在 javaFx 中找不到任何日期和时间选择器。即使我尝试了 JFxtras,但它不起作用。顺便说一句,我正在使用 javafx 2.2.3 和 java 7。任何帮助将不胜感激。

【问题讨论】:

  • 有机会升级到 Java 8 吗?
  • 不,先生。我只需要解决这个问题。
  • 您可以使用date picker created by Christian Schudt。教程可以关注Marco Jakob blog
  • 请注意,Java SE 7 计划在今年春天停产。建议届时升级到 Java SE 8 或与 Oracle 签订支持合同。
  • @SorcyCat:在 SE 7 中没有时间选择器。如果你是 java 8,你可以使用 jfxtras。

标签: javafx datepicker


【解决方案1】:

这是上面 DateTimePicker 控件的 Java 版本,略有改进。

此代码现在是 TornadoFX Controls 的一部分,您可以在 GitHub 存储库中查看最新版本的 DateTimePicker.java。该控件在 Maven Central 以及以下坐标下可用:

<dependency>
    <groupId>no.tornado</groupId>
    <artifactId>tornadofx-controls</artifactId>
    <version>1.0.3</version>
</dependency>

现在的实现:

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.DatePicker;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.util.StringConverter;

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

/**
 * A DateTimePicker with configurable datetime format where both date and time can be changed
 * via the text field and the date can additionally be changed via the JavaFX default date picker.
 */
@SuppressWarnings("unused")
public class DateTimePicker extends DatePicker {
    public static final String DefaultFormat = "yyyy-MM-dd HH:mm";

    private DateTimeFormatter formatter;
    private ObjectProperty<LocalDateTime> dateTimeValue = new SimpleObjectProperty<>(LocalDateTime.now());
    private ObjectProperty<String> format = new SimpleObjectProperty<String>() {
        public void set(String newValue) {
            super.set(newValue);
            formatter = DateTimeFormatter.ofPattern(newValue);
        }
    };

    public DateTimePicker() {
        getStyleClass().add("datetime-picker");
        setFormat(DefaultFormat);
        setConverter(new InternalConverter());

        // Syncronize changes to the underlying date value back to the dateTimeValue
        valueProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == null) {
                dateTimeValue.set(null);
            } else {
                if (dateTimeValue.get() == null) {
                    dateTimeValue.set(LocalDateTime.of(newValue, LocalTime.now()));
                } else {
                    LocalTime time = dateTimeValue.get().toLocalTime();
                    dateTimeValue.set(LocalDateTime.of(newValue, time));
                }
            }
        });

        // Syncronize changes to dateTimeValue back to the underlying date value
        dateTimeValue.addListener((observable, oldValue, newValue) -> {
            setValue(newValue == null ? null : newValue.toLocalDate());
        });

        // Persist changes onblur
        getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue)
                simulateEnterPressed();
        });

    }

    private void simulateEnterPressed() {
        getEditor().fireEvent(new KeyEvent(getEditor(), getEditor(), KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false));
    }

    public LocalDateTime getDateTimeValue() {
        return dateTimeValue.get();
    }

    public void setDateTimeValue(LocalDateTime dateTimeValue) {
        this.dateTimeValue.set(dateTimeValue);
    }

    public ObjectProperty<LocalDateTime> dateTimeValueProperty() {
        return dateTimeValue;
    }

    public String getFormat() {
        return format.get();
    }

    public ObjectProperty<String> formatProperty() {
        return format;
    }

    public void setFormat(String format) {
        this.format.set(format);
    }

    class InternalConverter extends StringConverter<LocalDate> {
        public String toString(LocalDate object) {
            LocalDateTime value = getDateTimeValue();
            return (value != null) ? value.format(formatter) : "";
        }

        public LocalDate fromString(String value) {
            if (value == null) {
                dateTimeValue.set(null);
                return null;
            }

            dateTimeValue.set(LocalDateTime.parse(value, formatter));
            return dateTimeValue.get().toLocalDate();
        }
    }
}

dateTimeValue 属性包含时间值,valueProperty 仅包含日期值。

我还没有为这个组件添加测试,所以实现可能会改变,请查看 GitHub 以获取最新版本。

【讨论】:

    【解决方案2】:

    JFXtras 项目有一个适用于 JavaFX 2.2 的工作版本。在 2.2 分支下的 repo 中查找 CalendarPickerCalendarTimePicker、...。

    您可以通过从jfxtras.org 下载最新版本 (2.2-r6-SNAPSHOT) 来测试它。

    这个简短的 sn-p 将创建一个用于选择日期和时间的日历:

    @Override
    public void start(Stage primaryStage) {
        CalendarPicker dateTime = new CalendarPicker();
        dateTime.withCalendar(Calendar.getInstance());
        dateTime.withShowTime(Boolean.TRUE);
        dateTime.withLocale(Locale.ENGLISH);
        dateTime.calendarProperty().addListener(new ChangeListener<Calendar>() {
    
            @Override
            public void changed(ObservableValue<? extends Calendar> ov, Calendar t, Calendar t1) {
                System.out.println("Selected date: "+t1.getTime().toString());
            }
        });
        StackPane root = new StackPane();
        root.getChildren().add(dateTime);
    
        Scene scene = new Scene(root, 300, 250);
        primaryStage.setTitle("Date & Time from JFXtras 2.2");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    

    【讨论】:

      【解决方案3】:

      我发现通过键盘输入时间而不是使用滑块更改时间最方便。将包含的 DatePicker 扩展为如下所示非常容易:

      我还发现 DatePicker 没有在 TextField onblur 中提交编辑后的值很烦人,所以下面的代码也修复了这个问题。

      为了简洁起见,sn-p 是用 Kotlin 编写的,您可以通过 IntelliJ IDEA 轻松地将其转换为 Java:

      import javafx.beans.property.SimpleObjectProperty
      import javafx.scene.control.DatePicker
      import javafx.scene.input.KeyCode
      import javafx.scene.input.KeyEvent
      import javafx.scene.input.MouseEvent
      import javafx.util.StringConverter
      import java.time.LocalDate
      import java.time.LocalDateTime
      import java.time.LocalTime
      import java.time.format.DateTimeFormatter
      
      class DateTimePicker(val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) : DatePicker() {
          private var dateTimeValue = SimpleObjectProperty<LocalDateTime>(LocalDateTime.now())
      
          init {
              converter = object : StringConverter<LocalDate>() {
                  override fun toString(value: LocalDate?): String {
                      return if (dateTimeValue.get() != null) dateTimeValue.get().format(formatter) else ""
                  }
      
                  override fun fromString(value: String?): LocalDate? {
                      if (value == null) {
                          dateTimeValue.set(null)
                          return null
                      }
      
                      dateTimeValue.set(LocalDateTime.parse(value, formatter))
                      return dateTimeValue.get().toLocalDate()
                  }
              }
      
              // Syncronize changes to the underlying date value back to the dateTimeValue
              valueProperty().addListener { observable, old, new ->
                  if (new == null) {
                      dateTimeValue.set(null)
                  } else {
                      if (dateTimeValue.get() == null) {
                          dateTimeValue.set(LocalDateTime.of(new, LocalTime.now()))
                      } else {
                          val time = dateTimeValue.get().toLocalTime()
                          dateTimeValue.set(LocalDateTime.of(new, time))
                      }
                  }
              }
      
              // Syncronize changes to dateTimeValue back to the underlying date value
              dateTimeValue.addListener { observable, old, new ->
                  valueProperty().set(new?.toLocalDate())
              }
      
              // Persist changes onblur
              editor.focusedProperty().addListener { observable, old, new ->
                  if (!new)
                      simulateEnterPressed()
              }
      
          }
      
          private fun simulateEnterPressed() =
              editor.fireEvent(KeyEvent(editor, editor, KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false))
      
          fun dateTimeValueProperty() = dateTimeValue;
      }
      

      将 LocalDateTime 属性绑定到 dateTimeValueProperty。

      【讨论】:

      • 你能把它作为java代码提供吗? (这是一个 java 问题,intelliJ 不是免费软件)
      • 好的,我会把它转换成Java代码并贴在这里。不过,IntelliJ 社区版是完全免费的。
      • 这仅适用于本地日期,但不适用于本地时间。我注意到造成这种情况的原因是您没有将本地时间坚持到 value 属性。当您从 value 属性推送更改时,本地时间不会分配给 datetimevalue 属性。
      【解决方案4】:

      与 NullableTimeStamp 一起使用的略微“改进”(至少满足我的需要)版本...以便能够将其归零(以便于使用 MySQL)...

      不知道这是否可以帮助任何人,但这里是:

      NullableTimeStamp:

      public class NullableTimestamp extends Timestamp {
      
          public NullableTimestamp() {
              super(0L);
          }
          public NullableTimestamp(long value) {
              super(value);
          }
      
          @Override
          public String toString() {
              return this.getTime() > 0L ? super.toString() : "";
          }
      
          public static NullableTimestamp valueOf(LocalDateTime localDateTime) {
              return new NullableTimestamp(Timestamp.valueOf(localDateTime).getTime());
          }
      }
      

      和日期时间选择器:

      public class DateTimePicker extends DatePicker {
          public static final String DefaultFormat = "yyyy-MM-dd HH:mm";
      
          private DateTimeFormatter formatter;
          private ObjectProperty<LocalDateTime> dateTimeValue = new SimpleObjectProperty<>(LocalDateTime.now());
          private ObjectProperty<String> format = new SimpleObjectProperty<String>() {
              public void set(String newValue) {
                  super.set(newValue);
                  formatter = DateTimeFormatter.ofPattern(newValue);
              }
          };
      
          public DateTimePicker() {
              getStyleClass().add("datetime-picker");
              setFormat(DefaultFormat);
              setConverter(new InternalConverter());
      
              // Syncronize changes to the underlying date value back to the dateTimeValue
              valueProperty().addListener((observable, oldValue, newValue) -> {
                  if (newValue == null) {
                      dateTimeValue.set(null);
                  } else {
                      if (dateTimeValue.get() == null) {
                          dateTimeValue.set(LocalDateTime.of(newValue, LocalTime.now()));
                      } else {
                          LocalTime time = dateTimeValue.get().toLocalTime();
                          dateTimeValue.set(LocalDateTime.of(newValue, time));
                      }
                  }
              });
      
              // Syncronize changes to dateTimeValue back to the underlying date value
              dateTimeValue.addListener((observable, oldValue, newValue) -> {
                  setValue(newValue == null ? null : newValue.toLocalDate());
              });
      
              // Persist changes onblur
              getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> {
                  if (!newValue)
                      simulateEnterPressed();
              });
      
          }
      
          private void simulateEnterPressed() {
              getEditor().fireEvent(new KeyEvent(getEditor(), getEditor(), KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false));
          }
      
          public LocalDateTime getDateTimeValue() {
              return dateTimeValue.get();
          }
      
          public void setDateTimeValue(LocalDateTime dateTimeValue) {
              if(dateTimeValue.isAfter(LocalDateTime.of(1971, 6, 30, 12, 00)))
                  this.dateTimeValue.set(dateTimeValue);
              else
                  this.dateTimeValue.set(null);
          }
      
          public ObjectProperty<LocalDateTime> dateTimeValueProperty() {
              return dateTimeValue;
          }
      
          public String getFormat() {
              return format.get();
          }
      
          public ObjectProperty<String> formatProperty() {
              return format;
          }
      
          public void setFormat(String format) {
              this.format.set(format);
          }
      
      class InternalConverter extends StringConverter<LocalDate> {
          public String toString(LocalDate object) {
      
              LocalDateTime value = getDateTimeValue();
              return (value != null) ? value.format(formatter) : "";
          }
      
          public LocalDate fromString(String value) {
              if (value == null) {
                  dateTimeValue.set(null);
                  return null;
              }
      
              dateTimeValue.set(LocalDateTime.parse(value, formatter));
              return dateTimeValue.get().toLocalDate();
              }
          }
      }
      

      它基本上掩盖了 0L 时间戳值,就好像它是 NULL...希望这可以帮助欢呼

      【讨论】:

        猜你喜欢
        • 2010-11-21
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-01
        • 1970-01-01
        相关资源
        最近更新 更多