java - 如果 ChangeListener 内焦点发生更改,DatePicker 不会提交值

标签 java javafx

The following issue is occurring with JDK 1.8 (8u231), Windows 10

我有一个 DatePicker 设置,其中包含一个监听器,当值更改时会显示 Alert。但是,一旦显示 AlertdatePicker.valueProperty() 就会恢复为其原始值。

这似乎并未“按设计工作”,并且其他多个开发人员已确认该问题在更高版本的 Java 中不存在。

这是一个要演示的 MCVE:

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;

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) {

                // Show an Alert
                Alert alert = new Alert(Alert.AlertType.WARNING);
                alert.setContentText("You selected " + newValue);
                alert.show();
                alert.setY(alert.getY()+100);
            }

        });

        root.getChildren().add(datePicker);

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

Alert 本身确实显示正确的日期,但 DatePicker valueProperty() 恢复为 null,如以下屏幕截图所示:

screenshot

使用 IntelliJ 的调试器,我可以确认 datePicker.valueProperty()alert.show() (或 alert .showAndWait()) 被调用。

Closest Potential Known Bugs:

我能够找到一些似乎相关的已知错误,但从 8u73 开始它们都已被标记为已解决(可能是回归?):

最佳答案

我能够在我当前使用的 JDK 版本中重现此问题。因此,经调查,根本原因是在将值提交给 textField 之前将焦点转移到新阶段(或从 DatePicker 失去焦点)。

在调试时我注意到以下结果:

  1. 当窗口焦点丢失时,焦点将转向所有子节点。
  2. 当焦点丢失时,ComboBoxPopupControl 会调用方法 setTextFromTextFieldIntoComboBoxValue。此时,如果您查看方法中的值,则 textField 的文本为空,并且“”为 null,导致将 null 值设置为comboBoxBase(突出显示的行)。

enter image description here 我认为我们可以通过两种方式对此进行调整:

选项#1: 以另一种方式采用@Kleopatra 解决方案,即在显示警报之前设置文本。这样我们就欺骗了 ComboBoxPopupControl->setTextFromTextFieldIntoComboBoxValue 方法,认为 textField 中有一个有效值,并且不让它重置该值。

选项#2: 将显示警报的部分包裹在 Platform.runLater 中,以处理稍后执行时显示的警报(此时提交将已在 DatePicker 中执行)。

这适用于手动输入的日期和在弹出窗口中选择的日期。

不确定此解决方法是否适合您。你能尝试一下吗?

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);
    }
}

关于java - 如果 ChangeListener 内焦点发生更改,DatePicker 不会提交值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59255211/

相关文章:

java - 使用鼠标绘制矩形

java - 是否可以从纯 Java 访问 Mac 地址簿 API?

java - 在使用 DFC 的 Documentum 中,我的文件夹迁移不断失败

JavaFX/SceneBuilder - 仅更改场景的一部分

JavaFX:运行 ChangeListener

java - HttpURLConnection.getInputStream() block

java - 在 .map() 中返回 null 与在 Reactor 中返回 .flatMap()

java - catch (Exception ex) block 未命中

java - 如何使用用户数据更新 JavaFX 中的 TreeView

java - 如何将外部 JS 脚本导入到 FXML 布局?