Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8094973

setDisable() inside DatePicker's setDayCellFactory not working if HijrahChronology is set

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 8u60
    • 8u31, 8u40
    • javafx
    • Windows 8.1 Pro 64bit - JDK 8 u40

      Ref: http://stackoverflow.com/q/28914579/597657

      I am trying to use JavaFX 8's DatePicker with disabling the days that are not in the range [today, today + 1 year], similar to [the example in the official tutorial][1]. Here is the code:

      **sample.fxml:**

          <?import javafx.scene.layout.GridPane?>
          <?import javafx.scene.control.DatePicker?>
          <GridPane fx:controller="sample.Controller"
                    xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
          
              <DatePicker fx:id="dpDate"/>
          
          </GridPane>

      **Main.java:**

          package sample;
          
          import javafx.application.Application;
          import javafx.fxml.FXMLLoader;
          import javafx.scene.Parent;
          import javafx.scene.Scene;
          import javafx.stage.Stage;
          
          public class Main extends Application {
          
              @Override
              public void start(Stage primaryStage) throws Exception{
                  Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
                  primaryStage.setTitle("Hello World");
                  primaryStage.setScene(new Scene(root, 300, 275));
                  primaryStage.show();
              }
          
          
              public static void main(String[] args) {
                  launch(args);
              }
          }

      **Controller.java:**

          package sample;
          
          import javafx.fxml.FXML;
          import javafx.fxml.Initializable;
          import javafx.scene.control.DateCell;
          import javafx.scene.control.DatePicker;
          import javafx.util.Callback;
          import javafx.util.StringConverter;
          
          import java.net.URL;
          import java.time.LocalDate;
          import java.time.chrono.HijrahChronology;
          import java.time.format.DateTimeFormatter;
          import java.util.ResourceBundle;
          
          public class Controller implements Initializable
          {
           private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
          
           @FXML private DatePicker dpDate;
          
           @Override
           public void initialize(URL location, ResourceBundle resources)
           {
           Callback<DatePicker, DateCell> dayCellFactory = dp -> new DateCell()
           {
           @Override
           public void updateItem(LocalDate item, boolean empty)
           {
           super.updateItem(item, empty);
          
           if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
           {
           setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
           setDisable(true);
           }
           }
           };
          
           StringConverter converter = new StringConverter<LocalDate>()
           {
           @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())
           {
           LocalDate date = LocalDate.parse(string, dateFormatter);
          
           if(date.isBefore(LocalDate.now()) || date.isAfter(LocalDate.now().plusYears(1)))
           {
           return dpDate.getValue();
           }
           else return date;
           }
          
           return null;
           }
           };
          
           dpDate.setDayCellFactory(dayCellFactory);
           dpDate.setConverter(converter);
           dpDate.setPromptText("dd/MM/yyyy");
           dpDate.setValue(LocalDate.now());
           dpDate.setChronology(HijrahChronology.INSTANCE);
           }
          }

      ![enter image description here][2]

      ---

      This example works (i.e. user cannot select out of the range) only if I remove the last line `dpDate.setChronology(HijrahChronology.INSTANCE);` and leave it with default `IsoChronology`.

      ![enter image description here][3]

      ---

      I have tried to consume the click event inside `updateItem()`:

          @Override
      public void updateItem(LocalDate item, boolean empty)
      {
      super.updateItem(item, empty);
              
      if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
      {
      setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
      setDisable(true);

      addEventFilter(MouseEvent.MOUSE_CLICKED, e -> e.consume());
      }
      }

      It works on the current month (the days before today cannot be selected). But if I go to the next months, it prevents the user from selecting a day from the permitted range.

      ---

      Definitely this is a bug. Is there a workaround? How can I access the date picker popup? Maybe I can attach a listener to the button that change the month page, and then iterate over all the say cells and disable the out-of-range days manually.

        [1]: http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/date-picker.htm#CCHEBIFF
        [2]: http://i.stack.imgur.com/tapAW.png
        [3]: http://i.stack.imgur.com/7BZwM.png

            leifs Leif Samuelsson (Inactive)
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: