TabPane Behaviour

Jose Martinez jmartine_1026 at
Sun Sep 16 05:53:43 PDT 2012


One thing that may or may not be useful but worth mentioning is to look into avoiding changing who has focus and just deal with the KeyEvents coming in from global perspective.  This is sort of what I tried to do on the OTN question that you commented on.  Then you will have access to the UP and DOWN keyCodes as well as the chars that are pressed and can act out on them... you have to set a filter to catch the UP and DOWN.

        root.addEventFilter(KeyEvent.ANY, rootKeyHandler);


 From: John Hendrikx <hjohn at>
To: openjfx mailing list <openjfx-dev at> 
Sent: Sunday, September 16, 2012 7:11 AM
Subject: TabPane Behaviour
Hi List,

This weekend I spent trying to make TabPane work properly when controlled by remote control.  This means that there are two important restrictions:

1) A remote control usually does not have keys for "Tab" and "Shift Tab" to 'escape' traversal contexts

2) The Application itself usually does not have input focus (as in keyboard focus) -- this is because it receives events by remote control no matter which application is focused.  This doesn't mean it cannot receive keyboard events while not focused -- the RC will send these to the App even when it does not have focus (this is the easiest way to make an application remote controlled usually).

I encountered the following difficulties:

1) When a TabPane has focus, it consumes all of the "Down", "Up", "Left" and "Right" keys, regardless of actual Tab orientation or whether or not the first or last tab was already selected.  For a remote control app, that means there is no way to exit the TabPane once it gets focus.

2) When the Stage does not have focus, but some other app does, TabPane does not respond to keys received by remote at all (most controls work fine, but TabPane does not).  I tracked this down to an "getControl().isFocused()" check in the TabPaneBehavior class -- I donot really understand why that check is there as I assume if you get those traversal events that you must be the focus owner already...

3) Once the content inside a Tab has focus, it again is impossible to leave this area with just the Up/Down/Left/Right navigation keys.

So, I spent a day hacking the TabPaneBehavior class, and in the process learning a bit about the internal traversal mechanism -- it looks pretty interesting already -- I'm hoping this will become public soon.  (Yes, I know this is not public API yet, and I know it might break at any time, but that's cool as my application is just a personal hobby project). Anyway, I've done the following:

1) I created a subclass of TabPaneSkin which does some reflection trickery in its constructor to remove the "standard" TabPaneBehaviour (which was just installed in the super constructor) and replace it with my own.  I did not see any mechanism to subclass a Skin and only provide a new Behavior.

2) I subclassed TabPaneBehavior (I had to subclass because there is an explicit cast somewhere to TabPaneBehavior in the TabPane code).

3) I only overrode the callAction method and changed it in the following way:
- Removed the isFocused checks
- Navigation keys consumed depend on the tab orientation (ie, Side.TOP or Side.BOTTOM only use "Left" and "Right")
- If first or last tab is already selected, we escape the TabPane traversal by calling BehaviorBase traversal methods
- If "Down" is pressed when tabs are Side.TOP then we navigate to the tab's content (same for "Right" when side == Side.LEFT, and so on).
- I never called super.callAction (as that would result in the wrong behavior) and instead called methods of BehaviorBase directly when I needed the focus to escape the TabPane.

4) This left me with one more problem, how to escape from the Tab itself when its content is focused... for that I wrapped the content in its own Pane.  This Pane keeps an eye on traversal occuring inside itself.  If any Traversal is unsuccesful, it will try and escape the Tab.  The solution I created here is a bit unsatisfactory because I donot know how to get the 'next higher' traversal engine to tell it to navigate up/down/left/right... instead when no focus change occured and the user pressed left or up, I translated this to "Previous", and down/right to "Next".

Anyway, I'm posting this in the hope it might be useful if this API is made public.  I did not see any JIRA issues I could comment on for this yet.  I can share the code to show exactly what I did to make the TabPane remote control friendly, and I'm hoping that in the future I can get this behavior using only public API.

John Hendrikx

More information about the openjfx-dev mailing list