[英]JavaFX datepicker not updating value
有點奇怪,我正在使用 JavaFX 8,並且在 Jubula 測試期間發現了一些奇怪的行為。
我有一個使用以下代碼創建的日期選擇器控件:
public DatePicker getDatePicker(DtDate defaultDate, int width){
DatePicker dtpckr = new DatePicker();
dtpckr.setMaxWidth(width);
dtpckr.setMinWidth(width);
dtpckr.setConverter(new StringConverter<LocalDate>() {
private DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy/MM/dd");
@Override
public String toString(LocalDate localDate) {
if(localDate==null)
return "";
return dateTimeFormatter.format(localDate);
}
@Override
public LocalDate fromString(String dateString) {
if(dateString==null || dateString.trim().isEmpty())
return null;
return LocalDate.parse(dateString,dateTimeFormatter);
}
});
dtpckr.setPromptText("yyyy/MM/dd");
dtpckr.setValue(LocalDate.parse(defaultDate.toString(), DateTimeFormatter.ofPattern("yyyy/MM/dd")));
return dtpckr;
}
這工作正常,控件在窗體上創建並按預期工作。 如果我使用日歷來選擇日期,則會更新該值。
現在,對於奇怪的部分,如果我輸入日期選擇器並手動輸入日期(例如 2017/10/11),然后通過制表符或單擊表單上的下一個文本框退出控件,則日期選擇器本地日期值不會不更新。 更新日期的唯一方法是按 Enter 鍵強制日期選擇器實現新值的存在。 這會導致另一個問題,因為我有以下代碼:
public void createSetDateAndTimeControls(){
DtDateAndTime currentDateAndTime;
try {
currentDateAndTime = systemstateController.getServerDateTime();
/*
* Creating controls to be used on the form
*/
int width = 150;
DatePicker dtpckr = getDatePicker(currentDateAndTime.date, width);
Label lblDate = new Label("Date:");
Label lblTimeHour = new Label("Hour:");
Label lblTimeMinute = new Label("Minute:");
Label lblTimeSecond = new Label("Second:");
TextField txtfldCurrentSetSecond = new TextField();
TextField txtfldCurrentSetMinute = new TextField();
TextField txtfldCurrentSetHour = new TextField();
Slider sldrHourPicker = getSlider(width, SliderType.Hour, txtfldCurrentSetHour, currentDateAndTime.time);
Slider sldrMinutePicker = getSlider(width, SliderType.Minute, txtfldCurrentSetMinute, currentDateAndTime.time);
Slider sldrSecondPicker = getSlider(width, SliderType.Second, txtfldCurrentSetSecond, currentDateAndTime.time);
/*
* Adding a grid pane to keep controls in correct place and aligned correctly
*/
GridPane grdpn = new GridPane();
grdpn.add(lblDate, 1, 1);
grdpn.add(dtpckr, 2, 1, 2,1);
grdpn.add(lblTimeHour, 1, 2);
grdpn.add(sldrHourPicker, 2, 2, 2 ,1);
grdpn.add(txtfldCurrentSetHour, 4, 2);
grdpn.add(lblTimeMinute, 1, 3);
grdpn.add(sldrMinutePicker, 2, 3, 2, 1);
grdpn.add(txtfldCurrentSetMinute, 4, 3);
grdpn.add(lblTimeSecond, 1, 4);
grdpn.add(sldrSecondPicker, 2, 4, 2, 1);
grdpn.add(txtfldCurrentSetSecond, 4, 4);
/*
* Creating buttons for user to press
*/
Button bttnOK = new Button("Change date and time");
bttnOK.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
try {
if (checkIfAllDialogHasBeenFilledIn(grdpn)){
LocalDate test = dtpckr.getValue();
if (systemstateController.oeSetClock(ICrashUtils.setDateAndTime(dtpckr.getValue().getYear(), dtpckr.getValue().getMonthValue(), dtpckr.getValue().getDayOfMonth(),
(int)Math.floor(sldrHourPicker.getValue()), (int)Math.floor(sldrMinutePicker.getValue()), (int)Math.floor(sldrSecondPicker.getValue()))).getValue())
showOKMessage("Updated", "Date and time was updated successfully");
else
showErrorMessage("Error", "There was an error updating the date and time");
}
else
showUserCancelledActionPopup();
} catch (ServerOfflineException | ServerNotBoundException e) {
showExceptionErrorMessage(e);
}
}
});
bttnOK.setDefaultButton(true);
grdpn.add(bttnOK, 2, 5, 3, 1);
Button bttnSetNow = new Button("Now");
bttnSetNow.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
dtpckr.setValue(LocalDate.now());
LocalTime time = LocalTime.now();
sldrHourPicker.setValue(time.getHour());
sldrMinutePicker.setValue(time.getMinute());
sldrSecondPicker.setValue(time.getSecond());
}
});
grdpn.add(bttnSetNow, 4, 1);
/*
* End of creating controls to be used on the form
*/
anchrpnActivator.getChildren().add(grdpn);
AnchorPane.setTopAnchor(grdpn, 0.0);
AnchorPane.setRightAnchor(grdpn, 0.0);
AnchorPane.setLeftAnchor(grdpn, 0.0);
AnchorPane.setBottomAnchor(grdpn, 0.0);
} catch (ServerOfflineException | ServerNotBoundException e) {
showExceptionErrorMessage(e);
}
}
其中有以下幾行:
bttnOK.setDefaultButton(true);
這意味着如果用戶在日期選擇器控件上的文本輸入期間按下 Enter 鍵,它會在用戶將數據放入其他控件之前觸發onaction
事件,而我並不特別想要那樣。
所以問題是,如果用戶在框中輸入文本,然后不按 Enter 鍵就離開了框,為什么dtpckr.getValue()
不會改變? 我找不到一個事件來調用用戶離開 datepicker 框或 datepicker 的屬性來獲取控件的文本值並將其與dtpckr.getValue()
的值進行比較。 有什么我在這里想念的嗎?
如果您需要更多信息,請與我們聯系!
看來這可能是 JavaFX 中當前日期選擇器設置中的一個錯誤
我可能必須刪除默認按鈕並在 Jubula 測試中按下回車鍵才能使其正常工作。 除非有人有其他選擇?
我上面添加的錯誤日志有答案 。 您可以通過以下代碼訪問文本框的字符串值:
datePicker.getEditor().getText();
因此,設置文本框值可以通過以下方式完成:
datePicker.setValue(datePicker.getConverter()
.fromString(datePicker.getEditor().getText()));
我正在向丟失的焦點事件添加一個事件,這將強制更新datepicker值
和工作代碼:
public DatePicker getDatePicker(DtDate defaultDate, int width){
DatePicker dtpckr = new DatePicker();
dtpckr.setMaxWidth(width);
dtpckr.setMinWidth(width);
dtpckr.setConverter(new StringConverter<LocalDate>() {
private DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy/MM/dd");
@Override
public String toString(LocalDate localDate) {
if(localDate==null)
return "";
return dateTimeFormatter.format(localDate);
}
@Override
public LocalDate fromString(String dateString) {
if(dateString==null || dateString.trim().isEmpty())
return null;
try{
return LocalDate.parse(dateString,dateTimeFormatter);
}
catch(Exception e){
//Bad date value entered
return null;
}
}
});
dtpckr.setPromptText("yyyy/MM/dd");
dtpckr.setValue(LocalDate.parse(defaultDate.toString(), DateTimeFormatter.ofPattern("yyyy/MM/dd")));
//This deals with the bug located here where the datepicker value is not updated on focus lost
//https://bugs.openjdk.java.net/browse/JDK-8092295?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
dtpckr.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (!newValue){
dtpckr.setValue(dtpckr.getConverter().fromString(dtpckr.getEditor().getText()));
}
}
});
return dtpckr;
}
我有同樣的問題。 有這個技巧來解決它:
Date date = DateConverter.toDate(datePicker.getEditor().getText());
其中DateConverter.toDate()
是將字符串轉換為日期的方法。
@Draken的回答需要額外的一點。 如果用戶鍵入無效日期,則代碼將拋出DateTimeParseException。 您可以模擬DatePicker自己的行為:
dtpckr.getEditor().focusedProperty().addListener((obj, wasFocused, isFocused)->{
if (!isFocused) {
try {
dtpckr.setValue(dtpckr.getConverter().fromString(dtpckr.getEditor().getText()));
} catch (DateTimeParseException e) {
dtpckr.getEditor().setText(dtpckr.getConverter().toString(dtpckr.getValue()));
}
}
});
我最近在最新的 JavaFX 版本中修復了這個問題: https : //github.com/openjdk/jfx/pull/679
因此,當 JavaFX 18-ea+9 發布時,您可以使用它並刪除解決方法。 :-)
我知道這有點離題,但有一段時間我的用戶沒有按 ENTER 提交,所以我這樣做了。
/**
* This will automatically submit the input on lost of focus, if it's typed but not submitted (with ENTER).
*
* @param picker to apply
*/
private void activateAutoSubmit(DatePicker picker) {
// On Focus Leave Listener
picker.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
try {
// Set typed text to DatePicker value
picker.setValue(picker.getConverter().fromString(picker.getEditor().getText()));
} catch (Exception e) {
// For wrong input return old value
picker.getEditor().setText(picker.getConverter().toString(picker.getValue()));
}
}
});
}
用法
@FXML
private DatePicker dateStart;
@FXML
private DatePicker dateEnd;
@FXML
private void initialize() {
...
activateAutoSubmit(dateStart);
activateAutoSubmit(dateEnd);
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.