This should certainly also become possible at some point.  There already is internal API to find the next/previous or left/right Node, it is more a question how to expose this as an API at this point.

For this specific case, you'd probably want to change focus in an ActionEvent, or possibly a KeyEvent handler that looks for ENTER.

Then in the handler you'd probably just want to ask Scene to move focus to the logical next Node.  When in an event handler, that could be something like:

      oneOfMyNodes.getScene().focusNext();

or:

      oneOfMyNodes.getScene().focus(Direction.NEXT);

From what I can see, these methods would be trivial to add to Scene, as all the traversal methods are already present there.  I also think that it would be the correct place to have them, as there is no focus without a Scene and Scene already has the focusOwner property.

Currently this all is already possible for the user, but you'd need to build your own util that finds the next Node (there are some simple rules for this, like finding the current child index in the parent, going up the stack of parents when on the last child, etc... I think I may have it somewhere in a utility already :))

--John


On 19/09/2024 20:30, Chuck Davis wrote:
Focus traversal in JavaFX is one of the two things I miss most about Swing.  With Swing we could access the policy and move to the next or previous object programmatically -- a feature that is sadly lacking in FX.  For those of us old enough to remember the good old days of character interfaces, hitting the enter key was the way to move to the next input field.  I still maintain that feature but I've had to write all the code myself and for each field it has to be hard coded -- a real nuisance and totally unnecessary if we could access the TraversalPolicy and call next() or previous() like we did in Swing.

For example, place characters in a TextField and hit the enter key to trigger an event.  Execute the method to process the verification, conversion, formatting and then TraversalPolicy.next() places focus on the next input field -- good old efficient input and finger action.  No unnecessary and inefficient hand movements.

My $.02 on this whole discussion in this and associated threads regarding addressing the FX TraversalPolicy.

On Thu, Sep 19, 2024 at 8:39 AM John Hendrikx <john.hendr...@gmail.com> wrote:

    I've been looking into how exactly navigation keys are being used
    in FX,
    and who is responsible for handling them:

    - Controls can choose to install navigational keys directly in their
    input map (using FocusTraversalInputMap::getFocusTraversalMappings)
    - Controls can choose to do nothing and leave navigation keys to
    bubble
    up to Scene, at which point Scene will act on any unconsumed
    navigation
    keys (in the same was as the traversal mappings would)

    Scene basically is capable of almost all navigation you could
    possibly
    want out of the box.  Any control that does not install navigation
    keys,
    and leaves said keys to bubble up gets navigation for **free**. 
    This is
    almost all controls in JavaFX, and it makes sense as Controls
    should not
    care about navigation, they should only care about key presses that
    affect them directly.  Navigation should be a concern somewhere
    higher
    up in the hierarchy.

    So why do some controls install their own navigation keys?

    There are two answers:

    1. For some controls, navigation is conditional. A Spinner only
    allows
    directional navigation for the left/right keys, or up/down keys
    depending on its orientation.
    2. There is an unfortunate choice in ScrollPane that consumes
    directional keys for scrolling purposes, and so if such keys were
    left
    to bubble up, they would not end up at Scene.  Any control supporting
    directional navigation therefore must **specifically** install these
    bindings directly, even though navigation is not their concern (a
    Button
    cares about being pressed, not about activating unrelated controls
    nearby).

    The ScrollPane eating directional keys is an odd choice. In order
    for it
    to do so one of the following must be true:

    - A control inside it has focus that should act on directional
    navigation, but forgot to install navigation bindings (a custom
    control).  Such a control would work perfectly when not part of a
    ScrollPane (as Scene would then handle directional navigation), but
    break when placed inside it.  Note that all JavaFX controls do this
    "properly".  I couldn't find any controls that would leave
    directional
    keys to bubble up for a ScrollPane to consume.

    - The ScrollPane itself has focus; this can only happen when directly
    selected with the mouse (or focus traversable is set to true) and no
    specific control inside the pane was selected.  The ScrollPane
    receives
    the ":focused" style, clearly indicating that it is the target for
    keyboard events to the user.

    In short, ScrollPane is making navigation a lot more complex
    within FX
    than it needs to be.  Especially custom controls that do not have
    access
    (currently) to install navigational bindings will suffer from
    this, and
    will have to resort to their own navigation implementation for
    directional keys when placed inside a ScrollPane.

    # Proposal

    I think ScrollPane violates what I think should be a fundamental
    rule.
    Keys should only be consumed by what the user perceives as the
    focused
    control (ie. the one outlined with a highlighted border), with the
    only
    exceptions being short cuts (from a menu) or mnemonics. Containers
    such
    controls happen to be placed in should NOT consume key events -- the
    container is not the control with the focus, and so would confuse the
    user.  Only ScrollPane is violating this currently.  Note that if the
    ScrollPane has focus itself (and it has the :focused highlight)
    then it
    is perfectly fine and expected for it to consume keys as much as
    it wants.

    This is why I think we should modify ScrollPane to not consume the
    directional keys, unless it specifically has the focus.  All other
    controls can then remove their navigational bindings and leave
    them to
    bubble up to Scene, cleaning up their behaviors so they can focus on
    other concerns.  Custom controls would no longer need to install
    navigational bindings either, and would not need to worry about being
    placed inside a ScrollPane and having their directional navigation
    broken.

    Optional, but recommended, controls like Spinner should only act
    on the
    directional keys intended for them, and leave the ones they can't
    use to
    bubble up.  So a vertical spinner would consume up/down for
    changing the
    spinner value, but would leave left/right untouched for Scene to
    handle.  Controls that install a full set of navigational keys (like
    Button, ListView and TitledPane) don't need to do so anymore.

    I think I will file a ticket for this soon, but I'm curious what
    others
    think of this analysis.

    Note that by solving this problem, the need to make navigation
    functionality available to custom controls severely diminishes as one
    can simple leave the KeyEvents responsible for standard navigation to
    bubble up (recommended as this may be different for each platform).

    --John

Reply via email to