Posted by: edsyrett | 27 November 2009

Focus Loops within Focus Loops


Some time back I created my Sliding Panel component and did a demo of it here.

The problem with this component as it stands is that the focus goes around all the focusable components, including those on the sliding panel.  In other words, you can tab around the TextInput controls on the main forms, and then focus will disappear off onto the TextInput controls on the sliding panel, even if it’s closed.  What is really required is a separate focus loop around the components in the sliding panel.

I started off just by creating a new instance of FocusManager and pointing it at the SlidingPanel instance.  That solution suffered from two problems:

  • Firstly whilst focus would correctly move around all the components within the sliding panel, focus in the parent form would also include the components in the panel.   This wasn’t really a surprise as the FocusManager in the parent form will just go right ahead and include all the focusable component that it finds in its children, which will include those in the sliding panel.
  • Secondly, I hit a big bug in SystemManager.  I just clicked on a TextInput in the sliding panel and the app crashed in SystemManager::mouseDownHandler(), on the line:
index = childList.getChildIndex(p);

The code in SystemManager assumes that all the members of the forms collection are either pop-ups or direct children of the SystemManager instance.  My new FocusManager automatically added itself to the forms collection, but it was somewhere in the middle of the display list, not a pop-up of child of the SystemManager.  So I had to fix this issue, and for now I’ve just put that whole section of code in a try/catch block so that it survives the call to childList.getChildIndex(p).

The next problem to solve was that focus in the main form continued around all the controls in the sliding panel.  This was relatively easy to fix just by setting the tabChildren property of the SlidingPanel class to false.  This meant that the FocusManager handling the main form stopped adding any focusable components within the sliding panel.

However, this had a major side-effect – the FocusManager handling the components contained in the sliding panel didn’t work at all.  The reason was that in addFocusables() there was a call to isTabVisible() which searches up the display list to see if any parent objects have tabChildren set to false.  Of course, this spotted that SlidingPanel had its tabChildren property set to false and concluded that all its children should be ignored for tabbing.  So I had to create my own SlidingPanelFocusManager which didn’t perform that test.

The end result is here.  You can tab around the 6 TextInput controls and focus won’t enter any of the sliding panels.  If you open a panel, however, focus will move around the controls within the panel, including the button to open or close the panel.  It all works, but the number of changes to the mx framework mean that it won’t see production for a while until I make sure that there aren’t any more side effects.


Responses

  1. Thanks for this it is exactly what I need.

  2. Thank you very much.
    You saved me lots of time wondering around…
    Hope others also find it useful and keeping doing your good work~!
    🙂

  3. I was trying to test your last result and spotted some problems.
    I use FB4.0 and when I imported the project, it was converted into Flex SDK 4.0 and it doesn’t build at all.
    Your new FocusManager have many methods unimplemented from IFocusManager interface and it throws error.
    Can you kindly give me ways to fix that probs?
    Thanks again.

    • Hi,

      I’m afraid my solution to the focus problems was created for SDK 3.x. Version 4.0 of the SDK is so radically different I would need to recreate a solution all over again, but right now I have neither the time nor the requirement as we are still using SDK 3.2…..

      Cheers,

      Ed.

  4. very good app 🙂

  5. hi,
    i’m using the slidingPanel width a percentage width and the sliding panel doesn’t work.

    I think that the problem is in createChildren() method of SlidingPanel.as:

    child.width = this.width – _tabSkin.width; (this.width = 0)

    any suggestions?

    thanks

    • Hi,

      I have updated the test apps to handle percentage widths of the sliding panel. As you correctly said, this.width was still 0 by the time createChildren() was called – with a percentage width, the Flex framework code needs to perform a layout and that will come after createChildren().

      In the new version, the positioning of the children in the sliding panel is done in onResize() at which point this.width has been calculated.

      Thanks for your post, and sorry it took so long for me to respond (got a new laptop from work to play with…:-D)

      Cheers,

      Ed.

      • thank you very much!!! now works also the resize 😉

  6. […] The busiest day of the year was March 23rd with 92 views. The most popular post that day was Focus Loops within Focus Loops. […]

  7. Hi,

    Great component and demo. I tried replicating by downloading the source and running it, gave me 13 errors and I am pasting them here… I use Flex 3.5 SDK. Also tried with 3.2 and got the same errors. Can you throw some light?

    1044: Interface method addChildBridge in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method addChildToSandboxRoot in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method deployMouseShields in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method dispatchEventFromSWFBridges in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method get swfBridgeGroup in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method getSandboxRoot in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method getTopLevelRoot in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method getVisibleApplicationRect in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method isDisplayObjectInABridgedApplication in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method isTopLevelRoot in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method removeChildBridge in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method removeChildFromSandboxRoot in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    1044: Interface method useSWFBridge in namespace mx.managers:ISystemManager not implemented by class mx.managers:SystemManager.

    Thanks in advance..

    Ram Iyer

    • Hi,

      Looking at the errors, I’m suspicious that you haven’t got a clean 3.2 SDK to build against – the methods like useSWFBridge aren’t familiar and I suspect they appeared in a version of the SDK later than 3.2. So to get my app working you might have to sort out your SDK.

      Alternatively, go right ahead and copy the functions over from your SDK to my version and publish it somewhere on the web, then everyone else can have a look.

      Cheers,

      Ed.

  8. You should include the slide out button of a sliding panel in the main focus loop so the user can tab to it and then slide out the panel by hitting Space.


Leave a comment

Categories