The following issue is occurring with JDK 1.8 (8u231), Windows 10
我有一个 DatePicker
设置,其中包含一个监听器,当值更改时会显示 Alert
。但是,一旦显示 Alert
,datePicker.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
,如以下屏幕截图所示:
使用 IntelliJ 的调试器,我可以确认 datePicker.valueProperty()
在 alert.show()
(或 alert .showAndWait()
) 被调用。
Closest Potential Known Bugs:
我能够找到一些似乎相关的已知错误,但从 8u73 开始它们都已被标记为已解决(可能是回归?):
最佳答案
我能够在我当前使用的 JDK 版本中重现此问题。因此,经调查,根本原因是在将值提交给 textField 之前将焦点转移到新阶段(或从 DatePicker 失去焦点)。
在调试时我注意到以下结果:
- 当窗口焦点丢失时,焦点将转向所有子节点。
- 当焦点丢失时,ComboBoxPopupControl 会调用方法 setTextFromTextFieldIntoComboBoxValue。此时,如果您查看方法中的值,则 textField 的文本为空,并且“值”为 null,导致将 null 值设置为comboBoxBase(突出显示的行)。
选项#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/