gpt4 book ai didi

datepicker - 使用 ONE JavaFX 8 DatePicker 选择期间或日期

转载 作者:行者123 更新时间:2023-12-04 19:05:03 25 4
gpt4 key购买 nike

在我当前工作的应用程序中,有必要从同一个 JavaFX 8 DatePicker 中选择一个日期或一个时间段。

这样做的首选方法如下:

  • 选择单个日期 - 与 DatePicker 的默认行为相同。
  • 选择一个时期 - 通过按住鼠标按钮并拖动到所需的结束/开始日期来选择开始/结束日期。当鼠标按钮被释放时,您已经定义了您的周期。您不能选择显示日期以外的日期这一事实是可以接受的。
  • 编辑应适用于单个日期(例如 24.12.2014)和期间(例如:24.12.2014 - 27.12.2014)

  • 上面所选时段(减去文本编辑器的内容)的可能呈现如下所示:

    Rendering of selected period

    橙色表示当前日期,蓝色表示选定期间。图片来自我制作的原型(prototype),但是使用 2 个 DatePicker 而不是一个来选择句点。

    我查看了源代码
    com.sun.javafx.scene.control.skin.DatePickerContent

    它有一个
    protected List<DateCell> dayCells = new ArrayList<DateCell>();

    为了找到一种方法来检测鼠标何时选择了鼠标释放时的日期结束(或者可能检测到拖动)。

    但是我不太确定该怎么做。有什么建议么?

    我附上了迄今为止我制作的简单原型(prototype)代码(使用 2 而不是所需的 1 日期选择器)。

    Prototype so far
    import java.time.LocalDate;

    import javafx.beans.property.SimpleObjectProperty;

    public interface PeriodController {

    /**
    * @return Today.
    */
    LocalDate currentDate();

    /**
    * @return Selected from date.
    */
    SimpleObjectProperty<LocalDate> fromDateProperty();

    /**
    * @return Selected to date.
    */
    SimpleObjectProperty<LocalDate> toDateProperty();
    }


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

    import javafx.util.StringConverter;

    public class DateConverter extends StringConverter<LocalDate> {

    private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); // TODO i18n

    @Override
    public String toString(LocalDate date) {
    if (date != null) {
    return dateFormatter.format(date);
    } else {
    return "";
    }
    }

    @Override
    public LocalDate fromString(String string) {
    if (string != null && !string.isEmpty()) {
    return LocalDate.parse(string, dateFormatter);
    } else {
    return null;
    }
    }


    }







    import static java.lang.System.out;

    import java.time.LocalDate;
    import java.util.Locale;

    import javafx.application.Application;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.geometry.HPos;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;

    public class PeriodMain extends Application {

    private Stage stage;

    public static void main(String[] args) {
    Locale.setDefault(new Locale("no", "NO"));
    launch(args);
    }

    @Override
    public void start(Stage stage) {
    this.stage = stage;
    stage.setTitle("Period prototype ");
    initUI();
    stage.getScene().getStylesheets().add(getClass().getResource("/period-picker.css").toExternalForm());
    stage.show();
    }

    private void initUI() {
    VBox vbox = new VBox(20);
    vbox.setStyle("-fx-padding: 10;");
    Scene scene = new Scene(vbox, 400, 200);


    stage.setScene(scene);
    final PeriodPickerPrototype periodPickerPrototype = new PeriodPickerPrototype(new PeriodController() {

    SimpleObjectProperty<LocalDate> fromDate = new SimpleObjectProperty<>();
    SimpleObjectProperty<LocalDate> toDate = new SimpleObjectProperty<>();

    {
    final ChangeListener<LocalDate> dateListener = (observable, oldValue, newValue) -> {
    if (fromDate.getValue() != null && toDate.getValue() != null) {
    out.println("Selected period " + fromDate.getValue() + " - " + toDate.getValue());
    }
    };
    fromDate.addListener(dateListener);
    toDate.addListener(dateListener);

    }


    @Override public LocalDate currentDate() {
    return LocalDate.now();
    }

    @Override public SimpleObjectProperty<LocalDate> fromDateProperty() {
    return fromDate;
    }

    @Override public SimpleObjectProperty<LocalDate> toDateProperty() {
    return toDate;
    }


    });

    GridPane gridPane = new GridPane();
    gridPane.setHgap(10);
    gridPane.setVgap(10);
    Label checkInlabel = new Label("Check-In Date:");
    GridPane.setHalignment(checkInlabel, HPos.LEFT);
    gridPane.add(periodPickerPrototype, 0, 1);
    vbox.getChildren().add(gridPane);
    }
    }







    import java.time.LocalDate;

    import javafx.beans.value.ChangeListener;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.control.DateCell;
    import javafx.scene.control.DatePicker;
    import javafx.scene.control.Label;
    import javafx.scene.control.Tooltip;
    import javafx.scene.layout.GridPane;
    import javafx.util.Callback;
    import javafx.util.StringConverter;


    /**
    * Selecting a single date or a period - only a prototype.
    * As long as you have made an active choice on the {@code toDate}, the {@code fromDate} and {@code toDate} will have the same date.
    */
    public class PeriodPickerPrototype extends GridPane {

    private static final String CSS_CALENDAR_BEFORE = "calendar-before";
    private static final String CSS_CALENDAR_BETWEEN = "calendar-between";
    private static final String CSS_CALENDAR_TODAY = "calendar-today";
    private static final boolean DISPLAY_WEEK_NUMBER = true;

    private Label fromLabel;
    private Label toLabel;

    private DatePicker fromDate;
    private DatePicker toDate;
    private StringConverter<LocalDate> converter;
    private PeriodController controller;
    private ChangeListener<LocalDate> fromDateListener;
    private ChangeListener<LocalDate> toDateListener;
    private Callback<DatePicker, DateCell> toDateCellFactory;
    private Callback<DatePicker, DateCell> fromDateCellFactory;
    private Tooltip todayTooltip;
    private boolean toDateIsActivlyChosenbyUser;

    public PeriodPickerPrototype(final PeriodController periodController)

    {
    this.controller = periodController;
    createComponents();
    makeLayout();
    createHandlers();
    bindAndRegisterHandlers();
    i18n();
    initComponent();
    }

    public void createComponents() {
    fromLabel = new Label();
    toLabel = new Label();
    fromDate = new DatePicker();
    toDate = new DatePicker();
    todayTooltip = new Tooltip();
    }

    public void createHandlers() {
    fromDate.setOnAction(event -> {
    if ((!toDateIsActivlyChosenbyUser) || fromDate.getValue().isAfter(toDate.getValue())) {
    setDateWithoutFiringEvent(fromDate.getValue(), toDate);
    toDateIsActivlyChosenbyUser = false;
    }

    });

    toDate.setOnAction(event -> toDateIsActivlyChosenbyUser = true);

    fromDateCellFactory = new Callback<DatePicker, DateCell>() {
    @Override public DateCell call(final DatePicker datePicker) {
    return new DateCell() {
    @Override
    public void updateItem(LocalDate item, boolean empty) {
    super.updateItem(item, empty);
    getStyleClass().removeAll(CSS_CALENDAR_TODAY, CSS_CALENDAR_BEFORE, CSS_CALENDAR_BETWEEN);

    if ((item.isBefore(toDate.getValue()) || item.isEqual(toDate.getValue())) && item.isAfter(fromDate.getValue())) {
    getStyleClass().add(CSS_CALENDAR_BETWEEN);
    }

    if (item.isEqual(controller.currentDate())) {
    getStyleClass().add(CSS_CALENDAR_TODAY);
    setTooltip(todayTooltip);
    } else {
    setTooltip(null);
    }
    }
    };
    }
    };

    toDateCellFactory =
    new Callback<DatePicker, DateCell>() {
    @Override
    public DateCell call(final DatePicker datePicker) {
    return new DateCell() {
    @Override
    public void updateItem(LocalDate item, boolean empty) {
    super.updateItem(item, empty);
    setDisable(item.isBefore(fromDate.getValue()));
    getStyleClass().removeAll(CSS_CALENDAR_TODAY, CSS_CALENDAR_BEFORE, CSS_CALENDAR_BETWEEN);


    if (item.isBefore(fromDate.getValue())) {
    getStyleClass().add(CSS_CALENDAR_BEFORE);
    } else if (item.isBefore(toDate.getValue()) || item.isEqual(toDate.getValue())) {
    getStyleClass().add(CSS_CALENDAR_BETWEEN);
    }
    if (item.isEqual(controller.currentDate())) {
    getStyleClass().add(CSS_CALENDAR_TODAY);
    setTooltip(todayTooltip);
    } else {
    setTooltip(null);
    }
    }
    };
    }
    };
    converter = new DateConverter();
    fromDateListener = (observableValue, oldValue, newValue) -> {
    if (newValue == null) {
    // Restting old value and cancel..
    setDateWithoutFiringEvent(oldValue, fromDate);
    return;
    }
    controller.fromDateProperty().set(newValue);
    };
    toDateListener = (observableValue, oldValue, newValue) -> {
    if (newValue == null) {
    // Restting old value and cancel..
    setDateWithoutFiringEvent(oldValue, toDate);
    return;
    }
    controller.toDateProperty().set(newValue);
    };

    }

    /**
    * Changes the date on {@code datePicker} without fire {@code onAction} event.
    */
    private void setDateWithoutFiringEvent(LocalDate newDate, DatePicker datePicker) {
    final EventHandler<ActionEvent> onAction = datePicker.getOnAction();
    datePicker.setOnAction(null);
    datePicker.setValue(newDate);
    datePicker.setOnAction(onAction);
    }

    public void bindAndRegisterHandlers() {
    toDate.setDayCellFactory(toDateCellFactory);
    fromDate.setDayCellFactory(fromDateCellFactory);
    fromDate.valueProperty().addListener(fromDateListener);
    fromDate.setConverter(converter);
    toDate.valueProperty().addListener(toDateListener);
    toDate.setConverter(converter);

    }

    public void makeLayout() {
    setHgap(6);
    add(fromLabel, 0, 0);
    add(fromDate, 1, 0);
    add(toLabel, 2, 0);
    add(toDate, 3, 0);

    fromDate.setPrefWidth(120);
    toDate.setPrefWidth(120);
    fromLabel.setId("calendar-label");
    toLabel.setId("calendar-label");
    }

    public void i18n() {
    // i18n code replaced with
    fromDate.setPromptText("dd.mm.yyyy");
    toDate.setPromptText("dd.mm.yyyy");
    fromLabel.setText("From");
    toLabel.setText("To");
    todayTooltip.setText("Today");
    }

    public void initComponent() {
    fromDate.setTooltip(null); // Ønsker ikke tooltip
    setDateWithoutFiringEvent(controller.currentDate(), fromDate);
    fromDate.setShowWeekNumbers(DISPLAY_WEEK_NUMBER);

    toDate.setTooltip(null); // Ønsker ikke tooltip
    setDateWithoutFiringEvent(controller.currentDate(), toDate);
    toDate.setShowWeekNumbers(DISPLAY_WEEK_NUMBER);
    }


    }

    /** period-picker.css goes udner resources (using maven) **/

    .date-picker {
    /* -fx-font-size: 11pt;*/
    }

    .calendar-before {
    }

    .calendar-between {
    -fx-background-color: #bce9ff;
    }

    .calendar-between:hover {
    -fx-background-color: rgb(0, 150, 201);
    }

    .calendar-between:focused {
    -fx-background-color: rgb(0, 150, 201);
    }

    .calendar-today {
    -fx-background-color: rgb(255, 218, 111);
    }

    .calendar-today:hover {
    -fx-background-color: rgb(0, 150, 201);
    }

    .calendar-today:focused {
    -fx-background-color: rgb(0, 150, 201);
    }

    #calendar-label {
    -fx-font-style: italic;
    -fx-fill: rgb(75, 75, 75);
    -fx-font-size: 11;
    }

    最佳答案

    我认为您已经走在正确的轨道上... DateCell并且拖动可以工作,因为如果检测到拖动事件或结束时弹出窗口不会关闭。这使您有机会跟踪用户选择的单元格。

    这是一个快速的技巧,但它可以帮助您选择范围。

    首先它将获取显示月份内所有单元格的内容和列表,添加一个监听器来拖动事件,将拖动开始的第一个单元格标记为第一个单元格,并选择第一个单元格内的所有单元格和下面的单元格实际鼠标位置,取消选择其余的。

    拖动事件完成后,选定的范围会显示在控制台上。您可以重新开始,直到弹出窗口关闭。

    private DateCell iniCell=null;
    private DateCell endCell=null;

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

    Scene scene = new Scene(new AnchorPane(datePicker), 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();

    datePicker.showingProperty().addListener((obs,b,b1)->{
    if(b1){
    DatePickerContent content = (DatePickerContent)((DatePickerSkin)datePicker.getSkin()).getPopupContent();

    List<DateCell> cells = content.lookupAll(".day-cell").stream()
    .filter(ce->!ce.getStyleClass().contains("next-month"))
    .map(n->(DateCell)n)
    .collect(Collectors.toList());

    content.setOnMouseDragged(e->{
    Node n=e.getPickResult().getIntersectedNode();
    DateCell c=null;
    if(n instanceof DateCell){
    c=(DateCell)n;
    } else if(n instanceof Text){
    c=(DateCell)(n.getParent());
    }
    if(c!=null && c.getStyleClass().contains("day-cell") &&
    !c.getStyleClass().contains("next-month")){
    if(iniCell==null){
    iniCell=c;
    }
    endCell=c;
    }
    if(iniCell!=null && endCell!=null){
    int ini=(int)Math.min(Integer.parseInt(iniCell.getText()),
    Integer.parseInt(endCell.getText()));
    int end=(int)Math.max(Integer.parseInt(iniCell.getText()),
    Integer.parseInt(endCell.getText()));
    cells.stream()
    .forEach(ce->ce.getStyleClass().remove("selected"));
    cells.stream()
    .filter(ce->Integer.parseInt(ce.getText())>=ini)
    .filter(ce->Integer.parseInt(ce.getText())<=end)
    .forEach(ce->ce.getStyleClass().add("selected"));
    }
    });
    content.setOnMouseReleased(e->{
    if(iniCell!=null && endCell!=null){
    System.out.println("Selection from "+iniCell.getText()+" to "+endCell.getText());
    }
    endCell=null;
    iniCell=null;
    });
    }
    });
    }

    这就是它的样子:

    Range selection on DatePicker

    目前这不会更新文本字段,因为这涉及使用自定义格式化程序。

    编辑

    我添加了一个自定义字符串转换器来显示文本字段上的范围,在完成选择之后,如果输入了有效的范围,还可以选择一个范围。

    这不是防弹的,但它可以作为概念证明。
    private DateCell iniCell=null;
    private DateCell endCell=null;

    private LocalDate iniDate;
    private LocalDate endDate;
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d.MM.uuuu", Locale.ENGLISH);

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

    @Override
    public String toString(LocalDate object) {
    if(iniDate!=null && endDate!=null){
    return iniDate.format(formatter)+" - "+endDate.format(formatter);
    }
    return object.format(formatter);
    }

    @Override
    public LocalDate fromString(String string) {
    if(string.contains("-")){
    try{
    iniDate=LocalDate.parse(string.split("-")[0].trim(), formatter);
    endDate=LocalDate.parse(string.split("-")[1].trim(), formatter);
    } catch(DateTimeParseException dte){
    return LocalDate.parse(string, formatter);
    }
    return iniDate;
    }
    return LocalDate.parse(string, formatter);
    }
    });
    Scene scene = new Scene(new AnchorPane(datePicker), 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();

    datePicker.showingProperty().addListener((obs,b,b1)->{
    if(b1){
    DatePickerContent content = (DatePickerContent)((DatePickerSkin)datePicker.getSkin()).getPopupContent();

    List<DateCell> cells = content.lookupAll(".day-cell").stream()
    .filter(ce->!ce.getStyleClass().contains("next-month"))
    .map(n->(DateCell)n)
    .collect(Collectors.toList());

    // select initial range
    if(iniDate!=null && endDate!=null){
    int ini=iniDate.getDayOfMonth();
    int end=endDate.getDayOfMonth();
    cells.stream()
    .forEach(ce->ce.getStyleClass().remove("selected"));
    cells.stream()
    .filter(ce->Integer.parseInt(ce.getText())>=ini)
    .filter(ce->Integer.parseInt(ce.getText())<=end)
    .forEach(ce->ce.getStyleClass().add("selected"));
    }
    iniCell=null;
    endCell=null;
    content.setOnMouseDragged(e->{
    Node n=e.getPickResult().getIntersectedNode();
    DateCell c=null;
    if(n instanceof DateCell){
    c=(DateCell)n;
    } else if(n instanceof Text){
    c=(DateCell)(n.getParent());
    }
    if(c!=null && c.getStyleClass().contains("day-cell") &&
    !c.getStyleClass().contains("next-month")){
    if(iniCell==null){
    iniCell=c;
    }
    endCell=c;
    }
    if(iniCell!=null && endCell!=null){
    int ini=(int)Math.min(Integer.parseInt(iniCell.getText()),
    Integer.parseInt(endCell.getText()));
    int end=(int)Math.max(Integer.parseInt(iniCell.getText()),
    Integer.parseInt(endCell.getText()));
    cells.stream()
    .forEach(ce->ce.getStyleClass().remove("selected"));
    cells.stream()
    .filter(ce->Integer.parseInt(ce.getText())>=ini)
    .filter(ce->Integer.parseInt(ce.getText())<=end)
    .forEach(ce->ce.getStyleClass().add("selected"));
    }
    });
    content.setOnMouseReleased(e->{
    if(iniCell!=null && endCell!=null){
    iniDate=LocalDate.of(datePicker.getValue().getYear(),
    datePicker.getValue().getMonth(),
    Integer.parseInt(iniCell.getText()));
    endDate=LocalDate.of(datePicker.getValue().getYear(),
    datePicker.getValue().getMonth(),
    Integer.parseInt(endCell.getText()));
    System.out.println("Selection from "+iniDate+" to "+endDate);

    datePicker.setValue(iniDate);
    int ini=iniDate.getDayOfMonth();
    int end=endDate.getDayOfMonth();
    cells.stream()
    .forEach(ce->ce.getStyleClass().remove("selected"));
    cells.stream()
    .filter(ce->Integer.parseInt(ce.getText())>=ini)
    .filter(ce->Integer.parseInt(ce.getText())<=end)
    .forEach(ce->ce.getStyleClass().add("selected"));
    }
    endCell=null;
    iniCell=null;
    });
    }
    });
    }

    Range selection and edition

    关于datepicker - 使用 ONE JavaFX 8 DatePicker 选择期间或日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27229168/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com