Select multiple dates with DatePicker

前端 未结 2 591
孤城傲影
孤城傲影 2021-01-14 02:39

I am trying to create a DatePicker that selects multiple dates. I am able to select multiple dates but I would like to keep the DatePicker open while I select them. Proble

相关标签:
2条回答
  • 2021-01-14 02:51

    If you check DatePickerContent class, you can find that each time a new DateCell is created, an EventHandler of type MOUSE_CLICKED is added to it. This handler will call selectDayCell(DateCell) when the user clicks on a cell. selectDayCell(DateCell) sets the new date value and hides the 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();
    }
    

    If you're using Java 9 or newer, you can extend DatePickerContent class and override the selectDayCell(DateCell) method to not hide the DatePicker after a cell is selected:

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

    Unfortunately, in Java 8, DatePickerContent has a package-private constructor so you can't extend from it. As a workaround, you can add another EventHandler on mouse click that will show the DatePicker again after a cell is clicked:

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

    In your cell factory:

    @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);
        }
    }
    
    0 讨论(0)
  • 2021-01-14 02:52

    Using M. S. answer, I was able to create this for 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;
            }
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题