java - 使用 DatePicker 的当前值作为另一个 DatePicker 的最小值/最大值
问题描述
我有一个允许用户指定时间跨度的 JavaFX UI。它由两个 DatePickers 组成,一个用于选择开始日期,一个用于选择时间跨度的结束日期。
显然,我不希望用户能够选择结束日期之后的开始日期,反之亦然。
我已经DayCellFactory
为两个日期选择器设置了自定义,如https://stackoverflow.com/a/46372951/5801146中所述。这适用于在 DatePickers 初始化期间指定的初始时间范围。但是,如果用户随后选择了不同的开始日期,则结束日期 DatePicker 仍会显示初始可选日期,并且不会将其可选日期调整为新的开始日期。这是我使用属性侦听器的方法,当然,这不起作用:
public final class DatePickerUtil {
public static void constrainLowerUpperBounds(DatePicker lowerBoundDatePicker, DatePicker upperBoundDatePicker) {
LocalDate lowerBound = lowerBoundDatePicker.getValue();
LocalDate upperBound = upperBoundDatePicker.getValue();
if (lowerBound.isAfter(upperBound)) {
throw new IllegalStateException("Upper bound date picker has older date than lower bound date picker");
}
lowerBoundDatePicker.setEditable(true);
upperBoundDatePicker.setEditable(true);
lowerBoundDatePicker.setDayCellFactory(createDayCellFactory(null, upperBound));
upperBoundDatePicker.setDayCellFactory(createDayCellFactory(lowerBound, null));
lowerBoundDatePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
upperBoundDatePicker.setDayCellFactory(createDayCellFactory(newValue, null));
});
upperBoundDatePicker.valueProperty().addListener(((observable, oldValue, newValue) -> {
lowerBoundDatePicker.setDayCellFactory(createDayCellFactory(null, newValue));
}));
}
private static Callback<DatePicker, DateCell> createDayCellFactory(LocalDate lowerBound, LocalDate upperBound) {
return picker -> new DateCell() {
@Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
boolean isBeforeLowerBound = lowerBound != null && date.isBefore(lowerBound);
boolean isAfterUpperBound = upperBound != null && date.isAfter(upperBound);
Platform.runLater(() -> setDisable(empty || isBeforeLowerBound || isAfterUpperBound));
}
};
}
}
我想要实现的是某种绑定,例如在 WPF/UWP 中,您可以将结束日期 DatePicker 的最小值绑定到开始日期 DatePicker 的当前值,并将开始日期 DatePicker 的最大值绑定到当前值结束日期 DatePicker。如何在 JavaFX 中实现这种行为?
解决方案
您可以将第一个DatePicker
的值传递给第二个,并在它更改后更新第二个。
这是一个简单的例子:
public class MinMaxDate {
private void test() {
DatePicker firstDP = new DatePicker();
DatePicker secondDP = new DatePicker();
// set the min date
secondDP.setDayCellFactory(cf -> new MinDateCell(firstDP.valueProperty()));
// set the max date
secondDP.setDayCellFactory(cf -> new MaxDateCell(firstDP.valueProperty()));
}
private class MinDateCell extends DateCell {
private ObjectProperty<LocalDate> date;
private MinDateCell(ObjectProperty<LocalDate> date) {
this.date = date;
}
@Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item.isBefore(date.get())) {
this.setDisable(true);
setStyle("-fx-background-color: #7e7e7e;"); // I used a different coloring to see which are disabled.
}
}
}
private class MaxDateCell extends DateCell {
private ObjectProperty<LocalDate> date;
private MaxDateCell(ObjectProperty<LocalDate> date) {
this.date = date;
}
@Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item.isAfter(date.get())) {
this.setDisable(true);
setStyle("-fx-background-color: #7e7e7e;"); // Same here
}
}
}
}
我创建了两个不同的类,但我确信可以使用一些花哨的 java8 函数来解决它,使其更通用,然后如果有任何条件禁用日期,您可以使用它。
更新
这是通用解决方案:
private class FilterDateCell extends DateCell {
private ObjectProperty<LocalDate> date;
private BiPredicate<LocalDate, LocalDate> filterPredicate;
private FilterDateCell(
ObjectProperty<LocalDate> date,
BiPredicate<LocalDate, LocalDate> filterPredicate) {
this.date = date;
this.filterFunction = filterFunction;
}
@Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (filterPredicate.test(item, date.get())) {
this.setDisable(true);
setStyle("-fx-background-color: #7e7e7e;"); // I used a different coloring to see which are disabled.
}
}
}
它可以像这样使用:
// set the min date
secondDP.setDayCellFactory(cf -> new FilterDateCell(firstDP.valueProperty(),LocalDate::isBefore));
// set the max date
secondDP.setDayCellFactory(cf -> new FilterDateCell(firstDP.valueProperty(),LocalDate::isAfter));
推荐阅读
- java - 得到关于不兼容类型问题的 .equals(),我如何制作我的 ArrayList
并点兼容并将答案转换为布尔值 - swift - 核心数据:对多谓词被忽略
- java - 从用户那里获取输入——这段代码中有什么不好的味道?
- assembly - 为什么偏移运算符返回一个巨大的偏移量,而变量位于 .data 段的开头?
- node.js - Discord.js:TypeError:无法读取未定义的属性“get”
- php - 比较星期几和小时到现在
- html - 为什么我的幻灯片会向下滚动屏幕?
- javascript - 排序字符串/数字数组Javascript
- javascript - 反应:无法在表单中读取未定义的属性“映射”
- c# - Visual Studio 中的更改不会影响虚幻引擎