Improvements for Focus Traversal code

Andy Goryachev andy.goryachev at oracle.com
Tue May 16 16:11:30 UTC 2023


I agree that focus management is one of the less developed parts of JavaFX.  In addition to all the scenarios listed by John and Chuck, there is a case where input is accepted by two controls at the same time


  *   JDK-8292933<https://bugs.openjdk.org/browse/JDK-8292933> Multiple focused components accepting keyboard input

I was thinking we could have a FocusManager that would keep track of where the focus is at any given time (across all the visible Stages), as well as FocusTraversalPolicy that governs traversal on a Stage or a Parent.  The FocusManager would expose a currentFocusOwner and a currentFocusedStage properies, provide programmatic focus traversal, manage the keys etc.

I also think Swing got the focus subsystem right, so perhaps we could consider doing something similar.  Would this change be backward compatible, or it will introduce breaking changes in the public APIs?

-andy


From: openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of Chuck Davis <cjgunzel at gmail.com>
Date: Tuesday, May 16, 2023 at 05:53
To:
Cc: openjfx-dev <openjfx-dev at openjdk.org>
Subject: Re: Improvements for Focus Traversal code
One of the things I really miss about Swing was the ease with which we could move focus programmatically.  All we had to do was call the focus object (don't remember the name) and call focus.next() or focus.previous().  Having to get the next Control and call Control.requestFocus() is a hack.  While the focus traversal code is being upgraded, please include Control.getFocusTraversal().next() and Control.getFocusTraversal().previous() so we can catch up with Swing capabilities.  Those of us old enough to have grown up with real computers still remember that focus from input to input is supposed to be done by pressing the "enter" key -- NOT the "tab" key.

On Tue, May 16, 2023 at 4:55 AM John Hendrikx <john.hendrikx at gmail.com<mailto:john.hendrikx at gmail.com>> wrote:
Hi list,

I've gone down another rabbit hole in JavaFX, this time related to focus
traversal.

# Navigation keys are not handled universally for all controls

Some controls install custom behaviors, and some don't.  The custom
behaviors often include direct handling of navigation keys
(getFocusTraversalMappings).  The controls that don't (often controls
that are not focus traversable by default, like Label) rely on the
SceneEventDispatcher to handle navigation keys.

However, this leads to subtle differences; when placed inside another
control that may be interested in the navigation keys (like ListView,
TableView, ScrollPane) a Button will still respond to all navigation
keys directly (and correctly), while a focus traversable Label will let
these events bubble up, possibly to be consumed by its parent (ie.
pressing DOWN may not focus another control inside the View, but instead
scroll the view down as if the View had focus).  This is inconsistent.

==> As any Node can be made focus traversable, I think the handling of
navigation keys should be done by Node itself; basically, after all
event handlers have run for a Node, a final event handler should be
called which checks for unconsumed navigation key events, and triggers
navigation only then.  This would make all Nodes work consistently where
navigation is concerned and would remove the need to add focus traversal
key mappings in Behaviors.  Button would respond as it always has, while
a focus traversable label would now work exactly as a Button would, even
when nested in a View type parent.

# Translate Navigation Keys to Higher Level Events

When a key is determined to trigger navigation, we should translate this
to a new type of event, for example NavigationEvent (or TraversalEvent).
This Key event that triggered it is consumed, and this new event is
fired.  This new event captures the intention to navigate somewhere
(Navigate NEXT, PREVIOUS, UP, DOWN, LEFT, RIGHT) and participates in the
usual filtering/bubbling phases.  This is far better than having a
(potentially platform specific) key event with multiple possible
meanings (sometimes it navigates, sometimes it scrolls) when one wants
to deal with navigation issues.

This would solve a number of problems:

- Navigation events can all be handled in the same place, the Scene.
- One can trigger navigation in a nice programmatic way, instead of
simulating a key press, which may be platform specific, one can send out
a NavigationEvent#NEXT event type.
- Influencing the focus traversal mechanism is much easier, as these
events can be listened to, filtered and consumed as needed. Contrast
this with trying to do this with key events which may have different
meanings depending on the state of the control receiving them.  Blocking
navigation for example is a matter of consuming a type of Navigation
event before it bubbles up to the Scene.
- It could allow for focus traversal that goes beyond Scenes (ie. focus
another Scene, or a Swing control).  Navigation events not consumed by
Scene could trigger other actions.  For NEXT/PREVIOUS navigation this
may require a Scene setting that prevents wrapping around to the
first/last control, and perhaps with the help of some further Navigation
event variations (like nagivating to FIRST or LAST).
- A lot of the Accessor code to be able to reach the (private) traverse
methods would not be needed anymore as the event system can reach the
Scene code without needing accessors

--John


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20230516/6c9ae67a/attachment-0001.htm>


More information about the openjfx-dev mailing list