Отключение дат в DatePicker без включения ранее отключенных дат

#java #javafx #datepicker #javafx-datepicker

Вопрос:

 import java.time.DayOfWeek;
import java.time.LocalDate;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;

public class Example extends Application {

    @Override public void start(Stage stage) {
        VBox container = new VBox();
        DatePicker datePicker = new DatePicker();
        disableSomeDates(datePicker);
        
        Button disableMondaysButton = new Button("No Mondays!");
        disableMondaysButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent arg0) {
                disableSomeMoreDates(datePicker);
            }
        });
        
        container.getChildren().add(datePicker);
        container.getChildren().add(disableMondaysButton);
        Scene scene = new Scene(container);

        stage.setScene(scene); 
        stage.sizeToScene(); 
        stage.show(); 
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
    
    public void disableSomeDates(DatePicker datePicker) {
        datePicker.setDayCellFactory(param -> new DateCell() {
            @Override
            public void updateItem(LocalDate date, boolean empty) {
                super.updateItem(date, empty);
                //Disables dates before current date
                setDisable(empty || date.compareTo(LocalDate.now()) < 0 );
            }
        }); 
    }
    
    public void disableSomeMoreDates(DatePicker datePicker) {
        datePicker.setDayCellFactory(param -> new DateCell() {
            @Override
            public void updateItem(LocalDate date, boolean empty) {
                super.updateItem(date, empty);
                //Disables mondays
                setDisable(empty || date.getDayOfWeek() == DayOfWeek.MONDAY);
            }
        }); 
    }
}
 

В этом примере кода я создаю указатель даты и отключаю некоторые даты (даты до сегодняшнего дня). Затем, нажав кнопку, он должен отключить понедельники, и, таким образом, мы должны отключить все даты до сегодняшнего дня и все понедельники. В этом случае мы закончим тем, что отключим только понедельники.

Как мне сделать так, чтобы кнопка отключала понедельники без повторного включения дат до сегодняшнего дня?

Ответ №1:

Я бы рекомендовал использовать фабрику с одной ячейкой, создавая ячейки, в которых наблюдаются свойства, которые затем можно изменить.

Напр.:

 import java.time.DayOfWeek;
import java.time.LocalDate;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Example extends Application {

    @Override public void start(Stage stage) {
        
        BooleanProperty mondaysDisabled = new SimpleBooleanProperty(false);
        
        VBox container = new VBox();
        DatePicker datePicker = new DatePicker();
        
        datePicker.setDayCellFactory(dp -> new DateCell() {
            
            {
                mondaysDisabled.addListener((obs, mondaysWereDisabled, mondaysAreNowDisabled) 
                    -> updateDisabledStatus());
            }
            
            @Override
            public void updateItem(LocalDate date, boolean empty) {
                super.updateItem(date, empty);
                updateDisabledStatus();
            }
            
            private void updateDisabledStatus() {
                if (isEmpty()) {
                    setDisable(true);
                } else {
                    LocalDate date = getItem();
                    if (date.isBefore(LocalDate.now())) {
                        setDisable(true);
                    } else {
                        if (mondaysDisabled.get() amp;amp; date.getDayOfWeek() == DayOfWeek.MONDAY) {
                            setDisable(true);
                        } else {
                            setDisable(false);
                        }
                    }
                }
            }
        });
        
        Button disableMondaysButton = new Button("No Mondays!");
        disableMondaysButton.setOnAction(event -> mondaysDisabled.set(true));
        
        container.getChildren().add(datePicker);
        container.getChildren().add(disableMondaysButton);
        Scene scene = new Scene(container);

        stage.setScene(scene); 
        stage.sizeToScene(); 
        stage.show(); 
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
    

}
 

Для чего-то более модульного подхода вы могли бы сохранить наблюдаемый список фильтров для проверки. Например.

 import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.function.Predicate;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Example extends Application {

    @Override public void start(Stage stage) {
        
        ObservableList<Predicate<LocalDate>> dayFilters = FXCollections.observableArrayList();
        dayFilters.add(date -> date != null);
        dayFilters.add(date -> ! date.isBefore(LocalDate.now()));
        
        VBox container = new VBox();
        DatePicker datePicker = new DatePicker();
        
        datePicker.setDayCellFactory(dp -> new DateCell() {
            
            {
                dayFilters.addListener((Change<? extends Predicate<LocalDate>> change) -> updateDisabledStatus());
            }
            
            @Override
            public void updateItem(LocalDate date, boolean empty) {
                super.updateItem(date, empty);
                updateDisabledStatus();
            }
            
            private void updateDisabledStatus() {
                setDisable(false);
                for (Predicate<LocalDate> check : dayFilters) {
                    if (! check.test(getItem())) {
                        setDisable(true);
                        break ;
                    }
                }
            }
        });
        
        Button disableMondaysButton = new Button("No Mondays!");
        disableMondaysButton.setOnAction(event -> dayFilters.add(date -> date.getDayOfWeek() != DayOfWeek.MONDAY));
        
        container.getChildren().add(datePicker);
        container.getChildren().add(disableMondaysButton);
        Scene scene = new Scene(container);

        stage.setScene(scene); 
        stage.sizeToScene(); 
        stage.show(); 
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
    

}