Hi Daniel,

thanks a lot for testing and giving valuable feedback!

Funny enough, I needed to implement the cell traversal you just described as well in an application. So I agree that this would be a good enhancement.

First of all, I don't think the InputMap implementation helps at all here.
For once, cells are not focus traversable by default (which is not influenced by the InputMap). And also you can just add a simple event handler. I don't see any benefit we would have with the InputMap.

And the biggest problem is the traversal logic. Finding the next editable cell is not easy. We need to check if the concrete cell is editable, the row, the table and the column. I implemented it by trying to edit a cell position and check if it 'worked' (we have an editing cell). We might be able to implement a somewhat more smart approach in the JFX internals.
In any case, this is indeed a good follow up at one point.

-- Marius

Am 18.03.2026 um 12:05 schrieb Daniel Peintner:
Hi Marius and all,

Thank you for your extensive work on this. Regarding PR #1935, I have had the opportunity to test the changes, and the functionality for committing values on focus loss appears to be working well. I would like to share a few common use cases we encounter when working with TableView in JavaFX:

- Cell Traversal: When a cell is in editing mode and the user presses "Tab," the subsequent cell should immediately enter editing mode (or Alt+Tab the other direction). - Selective Traversal: The ability to navigate through editable cells while skipping read-only cells for example - Editing Flow: F2 or a double-click should only be required for the initial entry into editing mode. Subsequently, the user should be able to navigate between cells and edit them directly (with keyboard only).

We currently have a solution that "works" (the attached video might give a better idea what I mean), but I believe developers often expect this functionality to be available out of the box. While PR #1935 is a significant step forward, we may want to consider additional features to support these specific workflows.

I am interested to hear your thoughts and if others agree that these additions would be beneficial.

Best regards,

-- Daniel


2026-03-18 11-40-34.gif


On Sat, Nov 15, 2025 at 5:27 PM Marius Hanl <[email protected]> wrote:

    Hey all,
    I did a lot of focus tests the last weeks and wrote a big sampler
    application as well.
    I will provide the source code as Gist in the PR description at
    one point.
    First of all, things look pretty good! There are some problematic
    cases, and at least one bug from what I can see.
    Note: All the problematic cases below also affect all other
    Controls that commit their value on focus loss, like DatePicker,
    Spinner, ...

    What works:
    - By default, the focus loss commit works well with all Controls
    out of the box
    - Mnemonics work. They will first request focus before they
    trigger the action
    Problematic cases:
    - A Tab selection change is fired before the focus is requested on
    the TabPane. While the focus lost commit still works, it is in my
    opinion too late. Think about disabling a Tab when something in a
    Table is invalid (which we know after the commit)
    - List/Tree/Table/View: Selection and focus is changed before the
    actual cell container will receive the focus. Even more weird: For
    both Tables, the selection change is fired BEFORE the focus
    change. List- and TreeView have the correct order. Again, in case
    we want to disable this Control when another Table is invalid,
    which we know right at the commit, we will still first trigger a
    selection and focus change
    Buggy cases:
    - As John also mentioned, non focus traversable Controls are
    completely broken. A non focus traversable Button or CheckBox will
    not request any focus. Therefore, Cells, DatePicker, ... can not
    commit their value. Other Controls set to non focus traversable
    like TextField or the TextField inside the DatePicker will request
    focus, the DatePicker button will not. This seems like a bug to
    me. Could also be something we want to ignore, as we can say: In
    this case, all focus loss commits are broken, so it is up to you.
    Feedback welcome
    Other cases:
    - MenuBar, Menu, MenuItem will not trigger focus at all. This
    might be expected. I don't know what to think about that. Feedback
    welcome
    -- Marius
    *Gesendet: *Freitag, 24. Oktober 2025 um 06:58
    *Von: *"Marius Hanl" <[email protected]>
    *An: *[email protected], [email protected],
    [email protected]
    *Betreff: *Re: Re: Re: Allowing a cell to commit the value on
    focus loss
    Those are good points. I will have a look. I do agree that the
    focus traversable behavior is questionable.
    I would expect that those problems also exist for Controls like
    the DatePicker, since it does also commit its value on focus loss.

    We might not be able to 'fix' mnemonics focus loss, in this case
    the responsibility is indeed an application responsibility.
    -- Marius
    *Gesendet: *Mittwoch, 15. Oktober 2025 um 18:52
    *Von: *"John Hendrikx" <[email protected]>
    *An: *"Andy Goryachev" <[email protected]>, "Marius Hanl"
    <[email protected]>, "[email protected]"
    <[email protected]>
    *Betreff: *Re: [External] : Re: Allowing a cell to commit the
    value on focus loss

    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 <[email protected]>
        <mailto:[email protected]>
        *Date: *Wednesday, October 15, 2025 at 08:05
        *To: *Marius Hanl <[email protected]>
        <mailto:[email protected]>, Andy Goryachev
        <[email protected]>
        <mailto:[email protected]>, [email protected]
        <[email protected]> <mailto:[email protected]>
        *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" <[email protected]>
            <mailto:[email protected]>
            *An: *"John Hendrikx" <[email protected]>
            <mailto:[email protected]>,
            "[email protected]" <mailto:[email protected]>
            <[email protected]> <mailto:[email protected]>
            *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 <[email protected]>
            <mailto:[email protected]> on behalf of John
            Hendrikx <[email protected]>
            <mailto:[email protected]>
            *Date: *Monday, October 13, 2025 at 07:17
            *To: *[email protected] <[email protected]>
            <mailto:[email protected]>
            *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, [email protected] 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
                
<https://urldefense.com/v3/__https://github.com/openjdk/jfx/pull/1935__;!!ACWV5N9M2RV99hQ!KeaTwOLaODiie2jQZ01j-vH00U9_nZNV8YxV6B0SXCExWnLFky0svIofyVK0ZPt0xawAISlouP_NCkqvMwFhYVHnQZte$>
                2* - https://bugs.openjdk.org/browse/JDK-8089514
                3* - https://bugs.openjdk.org/browse/JDK-8089311
                -- Marius

Reply via email to