Allowing a cell to commit the value on focus loss

John Hendrikx john.hendrikx at gmail.com
Wed Oct 15 15:04:59 UTC 2025


Hi Marius,

Focus lost is currently sort of a proxy of starting an interaction with
a new control, but not all controls gain focus when interacted with. 
Buttons are one of those (either with mouse press or keyboard short
cut), but there is I think also the scroll wheel that can interact with
a control without focusing it (and perhaps even popup menu's).

I can only think of one half-baked solution to this:

- Have a new Event type that is always targetted at the current focus
owner ("InterestLostEvent" ? :))
- This event is automatically fired by Scene just before an event is
fired that is not targetted at the current focus owner, AND the last
event fired did have the focus owner as target

What would happen in practice then would be something like:

- User edits field, keypress events go to current focus owner
- User does something else (moves mouse, scrolls, presses a hotkey, or
presses a button):
    - An InterestLostEvent is fired at the current focus owner BEFORE
the new event is fired
    - The delayed new event is now fired
    - No further InterestLostEvents are fired until the focus owner has
received a normal event again
- User goes back to editing after playing with the mouse; events
targetted at the focus owner renew the interest in that control, and so
next time an InterestLostEvent is fired again when needed

It feels a bit awkward, especially because simple things like mouse
moves may trigger it already (but a mouse move may trigger something
that requires the model to be up to date...); perhaps it would need to
be selective in some way so one can choose to only be interested in the
InterestLostEvent on focus loss and mouse clicks.

I can immediately see some problems as well.  Some controls I think
allow editing without focus gain/loss at all (I think some controls can
be edited by just scrolling the mouse wheel over them).  When should
those controls "commit" their values...?

--John


On 15/10/2025 16:39, Marius Hanl wrote:
> Hi John,
>  
> you are right that there might be corner cases. I hope that we could,
> what Andy suggests, find all cases and have a deeper look at them.
> We can also check whether the focus delegation API from Michael is
> something that could help us here (but might be completely unrelated).
>  
> The other options as you also mentioned, also have their problems.
> Even debouncing a commit on every keystroke can be unreliable if the
> user is too fast.
> I really hope we can make the focus loss reliable, as we then do not
> need much of an API changes inside the Cell Framework.
>  
> -- Marius
> *Gesendet: *Montag, 13. Oktober 2025 um 19:32
> *Von: *"Andy Goryachev" <andy.goryachev at oracle.com>
> *An: *"John Hendrikx" <john.hendrikx at gmail.com>,
> "openjfx-dev at openjdk.org" <openjfx-dev at openjdk.org>
> *Betreff: *Re: Allowing a cell to commit the value on focus loss
> I wonder if we should find out exactly why onFocusLost does not work
> in these cases, as expected.  Then, if I understand the proposal
> correctly, we won't need any API changes.
>  
> -andy
>  
>  
>  
> *From: *openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of John
> Hendrikx <john.hendrikx at gmail.com>
> *Date: *Monday, October 13, 2025 at 07:17
> *To: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
> *Subject: *Re: Allowing a cell to commit the value on focus loss
>
> Hi Marius,
>
> This may be unrelated, but it may be problematic to rely on committing
> values using focus lost:
>
> I've built a lot of code that relies on focus lost to "commit" values
> to some underlying model.  However, I noticed that a focus lost
> handler for committing values is insufficient when an action is
> triggered that doesn't trigger a loss of focus.   For example, if I
> have a field "email address" and a Button "Send Email", and I have a
> focus lost handler to commit the email address textfield to an
> underlying model, then pressing the Button will not trigger that
> handler and the underlying model may not have been updated with the
> latest edits.
>
> Solutions to trigger the correct action are all a bit tricky or annoying:
>
> - Query all fields for their current contents as focus lost is not
> entirely reliable for this purpose
> - Have fields update models immediately (which would be on every key
> press...) -- this is not very efficient, and can get in the way of
> validation / model restrictions
> - Have controls listen to a "COMMIT" event (this is fired at the
> current focus owner by the Button).  This event may be veto'd if
> committing the value resulted in a validation error, in which case the
> button press is cancelled
>
> I don't like any of these, but using the last option at the moment
> because I like constant updates and having to requery UI components
> even less...
>
> --John
>
>
> I noticed however that if you edit some field (it doesn't have to be
> in a table view, just a regular field), and have a focus lost handler
> that commits the value, that this focus lost handler is insufficient...
>
> On 13/10/2025 14:53, mariushanl at web.de wrote:
>
>     All,
>      
>     I created an initial poc 1* to support developers to commit the
>     cell value when the focus is lost 2* (including 3*).
>     More specifically, this gives the maximum flexibility to choose
>     what should happen when the focus is lost or the editing index
>     changed (which may happen when clicking into another cell while
>     editing).
>     All information mentioned here are also in the description of the PR.
>      
>     *API*
>     * *
>     - Instead of calling `/cancelEdit/`, every cell now calls
>     `/stopEdit/` when the focus is lost or the editing index changed.
>     The default behavior is cancelling the edit, but developers can
>     now override the behavior and allow a `/commitEdit/` instead
>     - There are multiple 'events' that can lead to a editing change.
>     Every change will now call `/stopEdit/`.
>     It is therefore the responsibility of the developer to decide,
>     when it makes sense to actually commit the value instead of
>     cancelling it. This decision was made as the behavior is
>     manipulating the editing index, but you as a developer can as
>     well. We do not really know what intention led to e.g. a change of
>     the editing index.
>     - Every `/MOUSE_PRESSED/` shifts the focus to the cell container,
>     which is undesired in case of editing the cell. So this event is
>     now consumed.
>     - All `/TextField/` cells now commit their value (instead of
>     cancel) on focus loss
>     - `/TextField/` Escape handling was badly implemented (it was
>     never really called, as the cell container handled Escape before)
>      
>     *Considerations*
>
>     - I tried to make the API minimal, and without breaking changes
>     (other than the `/TextField/` cells committing their values, but
>     we may split this up)
>     - The Cell Container focus behavior is, well, weird right now.
>     That is why consuming the event is needed to better support this
>     PR. One thing we may can consider is using the `/focusWithin/`
>     property instead for all 4 Cell Containers and not calling
>     `/requestFocus/` for nearly every `/MOUSE_PRESSED/` event. If we
>     decide so, this is needs to be done before merging this PR.
>     - Clicking the `/ScrollBar/` now commits/cancels the edit. I
>     checked other applications and this is very common. But something
>     I need to note here. This probably can be fixed in the same way
>     mentioned above (`/focusWithin/`)
>     - It might be hard for a developer to exactly know the cause why
>     `/stopEdit/` is called. This does not seem like a problem, as e.g.
>     for a `/TextField/`, you normally register listeners for e.g.
>     pressing the Escape key on it, so you keep full control.
>      
>     *Another Approach*
>
>     - Another Approach I tested could be to request the focus to a
>     cell when clicked/edited, to ensure that the focus listener is
>     ALWAYS called before another cell will reach the editing state.
>     Again, we probably need to change the focus handling to e.g. use
>     the `/focusWithin/` property. With this approach, we can only call
>     `/stopEdit` /when the focus changed (since it is now called
>     always), but not when the editing index changed.
>      
>     1* - https://github.com/openjdk/jfx/pull/1935
>     2* - https://bugs.openjdk.org/browse/JDK-8089514
>     3* - https://bugs.openjdk.org/browse/JDK-8089311
>      
>     -- Marius
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20251015/9234d700/attachment-0001.htm>


More information about the openjfx-dev mailing list