簡體   English   中英

JavaFX 日期選擇器不更新值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM