Search code examples
javafxdatepickerjavafx-datepicker

How do I change a property of all DatePickers in my project? (javaFX)


I have multiple DatePickers in my project and I want to make it so that the user cannot edit the text field and so they can't select a date before todays date on all of them.
I know how to do this to individual DatePickers but I want a way to apply this to all of them.
Here's the code I would use for them individually:

DatePicker datePicker = new DatePicker();
datePicker.getEditor().setDisable(true);
datePicker.getEditor().setOpacity(1);
datePicker.setDayCellFactory(param -> new DateCell() {
                @Override
                public void updateItem(LocalDate date, boolean empty) {
                    super.updateItem(date, empty);
                    setDisable(empty || date.compareTo(LocalDate.now()) < 0 );
                }
            });

Edit: As James_D commented I could just put these commands in a method which is the solution I used. Using a builder for this is also interesting, thanks for the detailed answer.


Solution

  • Use some kind of creational pattern, e.g. a builder pattern.

    Create an implementation of Builder<DatePicker>:

    import java.time.LocalDate;
    
    import javafx.scene.control.DateCell;
    import javafx.scene.control.DatePicker;
    import javafx.util.Builder;
    
    public class DatePickerBuilder implements Builder<DatePicker>{
    
        public DatePicker build() {
            DatePicker datePicker = new DatePicker();
            datePicker.getEditor().setDisable(true);
            datePicker.getEditor().setOpacity(1);
            datePicker.setDayCellFactory(param -> new DateCell() {
                @Override
                public void updateItem(LocalDate date, boolean empty) {
                    super.updateItem(date, empty);
                    setDisable(empty || date.compareTo(LocalDate.now()) < 0 );
                }
            });
            return datePicker ; 
    
        }
    }
    

    If you're creating your DatePickers in Java code, you can simply instantiate a DatePickerBuilder and use it:

    private final DatePickerBuilder datePickerBuilder = new DatePickerBuilder();
    
    // ...
    
    // any time you need a `DatePicker` do
    DatePicker datePicker = datePickerBuilder.build();
    

    If you're using FXML, you can wrap the DatePickerBuilder in a custom BuilderFactory:

    import javafx.fxml.JavaFXBuilderFactory;
    import javafx.scene.control.DatePicker;
    import javafx.util.Builder;
    import javafx.util.BuilderFactory;
    
    public class DatePickerBuilderFactory implements BuilderFactory {
    
        private final BuilderFactory defaultFactory ;
        private final DatePickerBuilder builder ;
        
        public DatePickerBuilderFactory() {
            defaultFactory = new JavaFXBuilderFactory();
            builder = new DatePickerBuilder();
        }
    
        @Override
        public Builder<?> getBuilder(Class<?> type) {
            if (type == DatePicker.class) {
                return builder;
            } else return defaultFactory.getBuilder(type) ;
        }
        
        
    }
    

    which you can then supply to your FXMLLoader:

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("path/to/fxml"));
        fxmlLoader.setBuilderFactory(new DatePickerBuilderFactory());
        Parent root = fxmlLoader.load();
    

    Deprecation note:

    The individual Builder classes defined in JavaFX version 2.0 were deprecated in version 8.0 due to an implementation error, and removed in version 9 as there was no clean way to fix that error.

    However, the BuilderFactory and Builder interfaces are still supported and used by the FXMLLoader, so this code is still supported.