Java 使用日期选择器的当前值作为另一个日期选择器的最小/最大值

Java 使用日期选择器的当前值作为另一个日期选择器的最小/最大值,java,javafx,Java,Javafx,我有一个JavaFXUI,允许用户指定时间跨度。它由两个日期选择器组成,一个用于选择时间跨度的开始日期,另一个用于选择时间跨度的结束日期 显然,我不希望用户能够选择在结束日期之后的开始日期,反之亦然 我已经为这两个日期选择器设置了自定义的DayCellFactory,如中所述。这在初始化日期选择器期间指定的初始时间范围内起作用。但是,如果用户随后选择不同的开始日期,则结束日期日期选择器仍会显示初始可选择日期,并且不会将其可选择日期调整为新的开始日期。下面是我使用属性侦听器的方法,当然,这不起作用

我有一个JavaFXUI,允许用户指定时间跨度。它由两个日期选择器组成,一个用于选择时间跨度的开始日期,另一个用于选择时间跨度的结束日期

显然,我不希望用户能够选择在结束日期之后的开始日期,反之亦然

我已经为这两个日期选择器设置了自定义的
DayCellFactory
,如中所述。这在初始化日期选择器期间指定的初始时间范围内起作用。但是,如果用户随后选择不同的开始日期,则结束日期日期选择器仍会显示初始可选择日期,并且不会将其可选择日期调整为新的开始日期。下面是我使用属性侦听器的方法,当然,这不起作用:

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));
            }
        };
    }
}
公共最终类DatePickerUtil{
公共静态void constraintLowerUpperBounds(日期选择器lowerBoundDatePicker,日期选择器upperBoundDatePicker){
LocalDate lowerBound=lowerBoundDatePicker.getValue();
LocalDate upperBound=upperBoundDatePicker.getValue();
if(下界isAfter(上界)){
抛出新的IllegalStateException(“上限日期选择器的日期早于下限日期选择器”);
}
lowerBoundDatePicker.setEditable(true);
upperBoundDatePicker.setEditable(true);
setDayCellFactory(createDayCellFactory(null,上限));
setDayCellFactory(createDayCellFactory(lowerBound,null));
lowerBoundDatePicker.valueProperty().addListener((可观察、旧值、新值)->{
setDayCellFactory(createDayCellFactory(newValue,null));
});
upperBoundDatePicker.valueProperty().addListener(((可观察,旧值,新值)->{
setDayCellFactory(createDayCellFactory(null,newValue));
}));
}
私有静态回调createDayCellFactory(LocalDate下限,LocalDate上限){
返回选择器->新建日期单元格(){
@凌驾
public void updateItem(LocalDate,布尔值为空){
super.updateItem(日期,空);
布尔值isBeforeLowerBound=lowerBound!=null&&date.isBefore(lowerBound);
布尔值isAfterUpperBound=上限!=null&&date.isAfter(上限);
Platform.runLater(()->setDisable(空的| | isBeforeLowerBound | | isAfterUpperBound));
}
};
}
}

我想要实现的是某种绑定,比如在WPF/UWP中,可以将结束日期日期选择器的最小值绑定到开始日期日期选择器的当前值,将开始日期日期选择器的最大值绑定到结束日期日期选择器的当前值。如何在JavaFX中实现这种行为?

您可以将第一个
日期选择器的值传递给第二个值,然后在它更改后更新第二个值

下面是一个简单的例子:

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
            }
        }

    }

}

谢谢@fabian,我在等一个更了解这一点并帮助我的人;)
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));