[External] : Re: Allowing a cell to commit the value on focus loss

John Hendrikx john.hendrikx at gmail.com
Wed Oct 15 16:52:45 UTC 2025


There is also the focus traversable flag that interacts with this, but
perhaps there is a bug.  When a button has focusTraversable set to
false, clicking it will not give it focus.  One may say that a property
named "focus traversable" would only affect focus *traversal* with the
keyboard (as I'd hardly call clicking with the mouse "traversal").

That still leaves mnemonic short-cuts and default actions for buttons
though.  Pretty sure those also don't focus the button and aren't
intended to, yet do execute the action.

--John

On 15/10/2025 17:20, Andy Goryachev wrote:
>
>  *
>     Buttons are one of those (either with mouse press or keyboard
>     short cut)
>
>
> This looks like a bug to me, really.  What is the main purpose of the
> focus subsystem?
> I know we like to reinvent the wheel, but focus in Swing works as
> expected, and one does get focus lost event on mouse press, and the
> target button gets the focus.  Why should FX be different?
>
> -andy  
>
>
> *From: *John Hendrikx <john.hendrikx at gmail.com>
> *Date: *Wednesday, October 15, 2025 at 08:05
> *To: *Marius Hanl <mariushanl at web.de>, Andy Goryachev
> <andy.goryachev at oracle.com>, openjfx-dev at openjdk.org
> <openjfx-dev at openjdk.org>
> *Subject: *[External] : Re: Allowing a cell to commit the value on
> focus loss
>
> 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/e1412e15/attachment-0001.htm>


More information about the openjfx-dev mailing list