DatePicker does not commit value if focus is changed within ChangeListener

I am able to reproduce this issue in the JDK version I am currently working. So on investigation, the root cause is getting focus on to new stage (or losing focus from DatePicker) before the value is committed to textField.

While debugging I noticed the below outcome:

  1. When window focus is lost, it turns of focus on all child nodes.
  2. ComboBoxPopupControl calls a method setTextFromTextFieldIntoComboBoxValue when focus is lost. At this point if you look at the value in the method, the textField's text is empty and the 'value' is null resulting in setting null value to the comboBoxBase(highlighted line).

enter image description here I think we can tweak this in two ways:

Option#1: Taking @Kleopatra solution in another way,i.e, by setting the text just before showing alert. This way we are fooling the ComboBoxPopupControl->setTextFromTextFieldIntoComboBoxValue method that there is a valid value in textField and not let it to reset the value.

Option#2: Wrap the part of the showing alert in Platform.runLater, to process the the alert showing at later point in execution (by that time the commit will be already performed in DatePicker).

This worked for both manually entered dates and dates selected in popup.

Not sure if this work around is suitable for you. Can you give a try?

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.time.LocalDate;

public class DatePickerCommit extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        DatePicker datePicker = new DatePicker();

        // Add listener on DatePicker
        datePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                // Option#1
               datePicker.getEditor().setText(datePicker.getConverter().toString(newValue));
               showAlert(newValue);

               // Option#2
               //Platform.runLater(()->showAlert(newValue));
            }
        });

        root.getChildren().add(datePicker);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Sample");
        primaryStage.show();
    }

    private void showAlert(LocalDate value){
        Alert alert = new Alert(Alert.AlertType.WARNING);
        alert.setContentText("You selected " + value);
        alert.show();
        alert.setY(alert.getY()+100);
    }
}

Tags:

Java

Javafx