Flex/Flash/Actionscript

Scrollable Menu Controls

As I was writing some stuff for the extended TabNavigator component that I’ve been working on (see some previous posts), I came across a need to use a PopUpMenuButton to list all the tabs, similar to how Firefox does this with the drop down list to the right of the tabs. This works great, except when there are a ton of tabs and the list gets really really long. Suddenly I realized that all the Menu controls in Flex have no option of adding a scrollbar to the menus. So if your menu is huge and goes off the stage, there’s nothing you can do about it and the menu items at the bottom are completely inaccessible.

mx.controls.Menu
So the complete inability to scroll a menu seemed a little weird to me, so I investigated and took a look into the mx.controls.Menu class. The answer to why the menus would never scroll is pretty obvious once you look at the code for the Menu control. The getter and setter for verticalScrollPolicy are these:


override public function get verticalScrollPolicy():String {
	return ScrollPolicy.OFF;
}

override public function set verticalScrollPolicy(value:String):void {
}

So if you were to try to set the verticalScrollPolicy of a Menu to ScrollPolicy.ON or ScrollPolicy.AUTO it wouldn’t do anything, and the scrollbars would remain off. There are a few other pieces in the code for Menu that don’t allow scrollbars, particularly in the configureScrollBars() and measure() methods.

So that’s no good if you want to allow scrollbars on your menus. The solution? An extension of mx.controls.Menu that overrides these problematic parts of the code. Basically I re-instituted the normal functionality for the getter and setter for verticalScrollPolicy, changed the configureScrollBars() method to actually configure the scrolling, and then modified measure() to take the scrollbars and new height restriction into account. Then we’ve got a new ScrollableMenu class that will allow you to set the maxHeight property. If the menu goes beyond maxHeight then the scrollbars are added, just like a normal scrolling control.

mx.controls.MenuBar
I also created a class that extended the MenuBar class, so it would use my new ScrollableMenu instead of the normal Menu when it created the Menus for the MenuBar. I was able to keep this extension fairly short, mostly just with an override of getMenuAt() and a private menu event listener.

So com.dougmccune.controls.ScrollableMenuBar lets you use the MenuBar control and specify a maxHeight, which will put a height limitation on the menus that popup when you click a menu item.

mx.controls.PopUpMenuButton
The PopUpMenuButton class was trickier. I initially tried to do a simple extension and get it to use the ScrollableMenu class instead of the normal Menu class, but this didn’t work so well. This was one of those cases (I’ve encountered this quite a bit) where the class you’re extending has private functions and variables that you need access to in order to accomplish your goals. I really didn’t need to make many changes to PopUpMenuButton, but because of the structure of the class I simply wasn’t able to make a clean extension.

So instead of extending PopUpMenuButton I had to copy/paste the entire class into a new class, and make the changes I needed. I’ve had to do this quite a few times to get custom components that I need. It’s obviously not ideal, you end up bloating your code base, but sometimes that’s the only option. But in the end we have a ScrollablePopUpMenuButton class that allows us to specify a maxHeight and that height will apply to all menus and submenus.

I’ve included the full source of all of these classes and the example below. I documented the code pretty well, so hopefully you can figure it out by taking a look. I wasn’t planning on uploading this one to Adobe Exchange, it doesn’t seem quite “componenty” enough. But if someone from Adobe thinks it belongs on the exchange then I’ll upload it, let me know in the comments.

View the source. UPDATE: See the next post for the current source of the component.

Here’s the example:

This movie requires Flash Player 9.

Standard

11 thoughts on “Scrollable Menu Controls

  1. You’ve sure been churning out a lot of components lately!

    I’d like to see the scrolling menu work like the Programs section in the Windows Start menu with arrows appearing at the top and bottom that react on mouseover rather than a scrollbar.

  2. Hey, nice looking scrollers. Sorry I missed you at the meet the Flex conference. I”ll send you an email off line and maybe we can still get together sometime and share apps.

  3. adeel anwar says:

    i found a bug in this component
    when we scroll the menu the sub menu values disturbed
    it shows wrong sub menu against the selected item.

  4. I am trying to use this component and have a question. When you invoke a menubaritem from the ScrollableMenuBar and select a menuitem from it’s dropdown menu, the next time you roll over or click the same menubaritem, it will not open. You have to roll to another menubaritem first or click on it twice. Using trace I noticed it only happens when getMenuAt overridden in the ScrollableMenuBar.as sees the menus[index] as a null menu and has to create a new one. I noticed that the ScrollableMenu remains in the menus array until you select a menuitem from it, then the next time getMenuAt looks the value is null again and it must create a new ScrollableMenu. I don’t know what the correct behaviour is and it may have nothing to do with the having to click twice.

    Can you shed any light on how to get the ScrollableMenuBar to not force the second click to get the menu to drop?

  5. A DeBonis says:

    I found the same problem and cant solve it

    After you choose a sub menu item > the next time you roll over or click the same menubaritem, it will not open.

    Any Ideas?

  6. A DeBonis says:

    Found the fix – this component is under FlexLib now… not sure why I didn’t catch that earlier. There is a fix posted to the latest code here
    http://code.google.com/p/flexlib/issues/detail?id=84&sort=flexlib&colspec=ID%20Type%20Status%20FlexLib%20Priority%20Milestone%20Owner%20Summary

    It works now after I applied the fix and rebuilt the swc.

    Fix:
    in ScrollableMenuBar.as in the eventHandler method, remove the line setting
    the local var ‘openMenuIndex’. Replace all remaining occurrences of
    ‘openMenuIndex’ with ‘this.selectedIndex’.

  7. Satish Ambig says:

    I am using this Scoll menubar, there is a issue, please help to fix.
    When we scroll the menu, the sub menu items are disturbed, it shuffles and shows wrong submenu for a selected item.

  8. Satish Ambig says:

    Showing wrong subMenu issue is fixed.
    Just remove IF condition from openSubMenu method of ScrollableArrowMenu class, i.e //if (!IMenuItemRenderer(row).menu) {

  9. Satish Ambig says:

    I am generating PDF from Flex using AlivePDF and it is working fine in all servers except SSO server. i need to fix this issue because my production is SSO.

    I am getting following error when I call java servlet

    Bad file request
    The request could not be understood by the server due to malformed syntax. Either there is a network problem, such as a time-out, or the request was indecipherable.

    I am creating byte Array and adding to url request like below,

    var header:URLRequestHeader = new URLRequestHeader (“Content-type”,”application/octet-stream”);
    var myRequest:URLRequest = new URLRequest (url+’?name=’+fileName+’&method=’+downloadMethod);
    myRequest.requestHeaders.push (header);
    myRequest.method = URLRequestMethod.POST;
    myRequest.contentType = “multipart/form-data”;
    myRequest.data=byteArray;

    Please help me to solve this issue

Comments are closed.