【问题标题】:Select multiple dates with DatePicker使用 DatePicker 选择多个日期
【发布时间】:2020-06-19 15:26:44
【问题描述】:

我正在尝试创建一个选择多个日期的 DatePicker。我可以选择多个日期,但我希望在选择日期时保持 DatePicker 处于打开状态。问题是,每次我选择日期时,DatePicker 都会关闭。

我不想使用私有 API。我正在考虑添加这个:

datePicker.setOnHiding(event -> {            
    event.consume();
});

但它不起作用。

这是我的代码:

public static DatePicker getDatePicker() {
    ObservableList<LocalDate> selectedDates = FXCollections.observableArrayList();
    String pattern = "yyyy-MM-dd";
    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    DatePicker datePicker = new DatePicker();
    datePicker.setPromptText(pattern);

    datePicker.setConverter(new StringConverter<LocalDate>() {
        @Override
        public String toString(LocalDate date) {
            return (date == null) ? "" : dateFormatter.format(date);
        }

        @Override
        public LocalDate fromString(String string) {
            return ((string == null) || string.isEmpty()) ? null : LocalDate.parse(string, dateFormatter);
        }
    });

    datePicker.setOnAction(event -> {
        selectedDates.add(datePicker.getValue());
        event.consume();
    });

    datePicker.setDayCellFactory((DatePicker param) -> new DateCell() {
        @Override
        public void updateItem(LocalDate item, boolean empty) {
            super.updateItem(item, empty);
            boolean alreadySelected = selectedDates.contains(item);
            setDisable(alreadySelected);
            setStyle(alreadySelected ? "-fx-background-color: #09a30f;" : "");
        }
    });

    return datePicker;
}

【问题讨论】:

    标签: java javafx datepicker date-range


    【解决方案1】:

    如果你检查DatePickerContent类,你会发现每次创建一个新的DateCell,都会添加一个MOUSE_CLICKED类型的EventHandler。当用户单击单元格时,此处理程序将调用selectDayCell(DateCell)selectDayCell(DateCell) 设置新的日期值并隐藏DatePicker

    protected void createDayCells() {
        final EventHandler<MouseEvent> dayCellActionHandler = ev -> {
            if (ev.getButton() != MouseButton.PRIMARY) {
                return;
            }
            DateCell dayCell = (DateCell)ev.getSource();
            selectDayCell(dayCell);
            lastFocusedDayCell = dayCell;
        };
        for (int row = 0; row < 6; row++) {
            for (int col = 0; col < daysPerWeek; col++) {
                DateCell dayCell = createDayCell();
                dayCell.addEventHandler(MouseEvent.MOUSE_CLICKED, dayCellActionHandler);
                dayCells.add(dayCell);
            }
        }
        dayCellDates = new LocalDate[6 * daysPerWeek];
    }
    
    public void selectDayCell(DateCell dateCell) {
        datePicker.setValue(dayCellDate(dateCell));
        datePicker.hide();
    }
    

    如果您使用的是 Java 9 或更高版本,您可以扩展 DatePickerContent 类并覆盖 selectDayCell(DateCell) 方法,以便在选择单元格后不隐藏 DatePicker

    public void selectDayCell(DateCell dateCell) {
        datePicker.setValue(dayCellDate(dateCell));
    }
    

    不幸的是,在 Java 8 中,DatePickerContent 有一个包私有构造函数,所以你不能从它扩展。作为一种解决方法,您可以在单击鼠标时添加另一个 EventHandler,它会在单击单元格后再次显示 DatePicker

    EventHandler<MouseEvent> mouseClickedEventHandler = clickEvent -> {
        if (clickEvent.getButton() == MouseButton.PRIMARY) {
            datePicker.show();
        }
        clickEvent.consume();
    };
    

    在您的细胞工厂中:

    @Override
    public void updateItem(LocalDate item, boolean empty) {
        super.updateItem(item, empty);
        //...
        if (item != null && !empty) {
            //...
            addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
        } else {
            //...
            removeEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
        }
    }
    

    【讨论】:

      【解决方案2】:

      使用 Chanandler Bong 小姐的回答,我能够为 JavaFX8 创建这个:

      public class MultiDatePicker
      {
      
          private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
          private final ObservableSet<LocalDate> selectedDates;
          private final DatePicker datePicker;
      
          public MultiDatePicker()
          {
              this.selectedDates = FXCollections.observableSet(new TreeSet<>());
              this.datePicker = new DatePicker();
              setUpDatePicker();
          }
      
        
          public ObservableSet<LocalDate> getSelectedDates()
          {
              return this.selectedDates;
          }
      
          public DatePicker getDatePicker()
          {
              return this.datePicker;
          }
      
          private void setUpDatePicker()
          {
              this.datePicker.setConverter(new StringConverter<LocalDate>()
              {
                  @Override
                  public String toString(LocalDate date)
                  {
                      return (date == null) ? "" : DATE_FORMAT.format(date);
                  }
      
                  @Override
                  public LocalDate fromString(String string)
                  {
                      return ((string == null) || string.isEmpty()) ? null : LocalDate.parse(string, DATE_FORMAT);
                  }
              });
      
              EventHandler<MouseEvent> mouseClickedEventHandler = (MouseEvent clickEvent) ->
              {
                  if (clickEvent.getButton() == MouseButton.PRIMARY)
                  {
                      if (!this.selectedDates.contains(this.datePicker.getValue()))
                      {
                          this.selectedDates.add(datePicker.getValue());
      
                      } else
                      {
                          this.selectedDates.remove(this.datePicker.getValue());
      
                          this.datePicker.setValue(getClosestDateInTree(new TreeSet<>(this.selectedDates), this.datePicker.getValue()));
      
                      }
      
                  }
                  this.datePicker.show();
                  clickEvent.consume();
              };
      
              this.datePicker.setDayCellFactory((DatePicker param) -> new DateCell()
              {
                  @Override
                  public void updateItem(LocalDate item, boolean empty)
                  {
                      super.updateItem(item, empty);
      
                      //...
                      if (item != null && !empty)
                      {
                          //...
                          addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
                      } else
                      {
                          //...
                          removeEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
                      }
      
                      if (selectedDates.contains(item))
                      {
      
                          setStyle("-fx-background-color: rgba(3, 169, 244, 0.7);");
      
                      } else
                      {
                          setStyle(null);
      
                      }
                  }
              });
      
          }
      
          private static LocalDate getClosestDateInTree(TreeSet<LocalDate> dates, LocalDate date)
          {
              Long lower = null;
              Long higher = null;
      
              if (dates.isEmpty())
              {
                  return null;
              }
      
              if (dates.size() == 1)
              {
                  return dates.first();
              }
      
              if (dates.lower(date) != null)
              {
                  lower = Math.abs(DAYS.between(date, dates.lower(date)));
              }
              if (dates.higher(date) != null)
              {
                  higher = Math.abs(DAYS.between(date, dates.higher(date)));
              }
      
              if (lower == null)
              {
                  return dates.higher(date);
              } else if (higher == null)
              {
                  return dates.lower(date);
              } else if (lower <= higher)
              {
                  return dates.lower(date);
              } else if (lower > higher)
              {
                  return dates.higher(date);
              } else
              {
                  return null;
              }
          }
          
      }
      

      【讨论】:

        猜你喜欢
        • 2018-11-15
        • 1970-01-01
        • 2014-11-01
        • 2010-11-29
        • 1970-01-01
        • 2020-03-26
        • 1970-01-01
        • 2020-11-25
        • 1970-01-01
        相关资源
        最近更新 更多