Skip to content

CommitOnFocusLost

Jeanette Winzenburg edited this page Aug 14, 2019 · 12 revisions
Note
this is a half-hearted draft …​ the initial trigger was bug JDK-8136838 in committing (which is fixed), further intention was to explore extended usage of TextFormatter. There’s also a related draft with slightly different focus (or not, we’ll see)

Commit Text Edits

Reported Issues

Created

2012-05-10 00:09

Status

fixed, 2012-05-24 22:51

Implementation note: was fixed by adding a focusListener in ComboBoxListViewSkin which calls setTextFromTextFieldToComboBox (aka: commit)

Created

2015-09-21 18:14

Status

fixed and backported, 2015-10-02 05:02

All text-like input controls (that is editable combo, picker, spinner - actually, the spinner isn’t mentioned nor addressed in the fix!) should commit an edited value on focusLost. This issue was evaluated as a regression of JDK-8120120 introduced by fixing an issue of editable combo and picker in combination with default buttons: that one added tweaks in ComboBoxBaseBehaviour, DatePickerBehaviour and ComboBoxPopupControl, the latter taking over some event dispatching …​

Implementation note: fixed by adding focusListener in ComboBoxPopupControl which calls setTextFromTextFieldToComboBox (aka: commit). The analysis was that the focusListener was lost …​ but that’s wrong: was still there (but not reached

Created

2016-03-03 10:05

Status

duplicate of JDK-8150946

Listeners to the focusedProperty are notified before the edited text is committed. That’s inconsistent with the behavior of a TextField which has a TextFormatter attached: in this case the formatter’s value is already updated at the time of being notified. Duplicate not technically, but for process reasons.

Implementation note: the main issue here is the requirement for a stable sequence of listener notification: custom listeners must be guaranteed to be notified after system-installed listeners. That’s the reason for installing the listener on the control (vs. by the skin). Has precedence for TextInputControl, works fine.

Created

2016-03-01 12:18

Status

fixed, 2016-06-21 01:46

Fix adds commit/cancel api to ComboBox and Spinner (and forgot DatePicker!) and use the commit in a focusListener.

Implementation note: moved focusListener from skin into control.

Created

2017-11-28 15:17

Status

open

Regression introduced by a combination of moving focusListener from skin into control and forgetting DatePicker in adding commit/cancel api.

Definition

After a user edited a textual input they indicate the termination of the edit by one of various gestures

  • press a edicated key, typically ENTER (though might be others, like f.i. F2 in tabular contexts)

  • press/click a button that will process the changed data

  • simply tab away

The first two strong gestures, the last a more vague indication.

A commit might f.i. involve a conversion of the text into some other data type or simply trigger a dirty marker such that sometime later the application doesn’t forget to save any changed data.

Detection

Input controls like f.i. a TextField support commits via a dedicated key (pending jw can we change/add the/a key easily?) - they fire an ActionEvent. Application code can listen and trigger what’s needed. At the other end, client code on a button handler can pro-actively commit changes.

The last is trickier to detect: in fact only indirectly via observing a change of focus owner (either on the text input itself or the global owner on the scene).

Advanced Support

Since 8u40, JavaFx has a TextFormatter. The formatter has a value property that is kept in sync with a (text) control’s text property at all times that are considered stable (aka: committed). Specifically, the field’s text is updated whenever the formatter’s value changes. The other way round, the formatter’s value is updated when the text’s input is committed. For a giving field/formatter pair, such a commit is

  • user hits ENTER

  • control looses focus

  • field.setText is called programmatically (this is only documented in the private class TextProperty in TextInputControl, strictly speaking it’s unspecified!)

The TextFormatter guarantees to update its value on focusLost. It’s updated "early enough" such that listeners to the focusedProperty can rely on the value being updated and in sync with the text. This expected behavior is technically achieved by having the TextInputControl itself listening to the focusedProperty and committing any pending edits. On the other hand, the text-like input controls have their skins listening and committing: in typical use-cases, the listener in the skin is registered after listeners installed by application code. As a consequence, the value is not yet updated.

To make the behavior consistent across text/like input controls, options include

  • some type of hook into the listener chain such that skins can register listeners at the start (improbable, would require deep changes in the Observable/Property realm

  • let the text-like controls install a focus listener themselves, just as a plain TextInput control does.

As its simplest, that would be something like (TBD: use converter!)

ComboBox<String> comboBox = new ComboBox<String>(items) {
    {
        focusedProperty().addListener((src, ov, nv) -> {
            if (!nv && isEditable()) {
                setValue(getEditor().getText());
            }
        });
    }

};

A deeper solution might be to add commit/cancel semantics plus TextFormatter support to all text-like controls. Support of the latter competes with the already available support of StringConverter, both must be merged.