Tuesday, January 26, 2010

Flex Context Menus

I've had some frustration with Flex ContextMenus, so I thought I'd write an entry about the basics of creating context menus, adding items, listening for context menu events, and a few restrictions on context menus.

Every InteractiveObject (e.g. Application, Panel, Button, etc) contains a contextMenu property. For most components it will be null and you'll have to create a new menu and assign it to that property. So you can have different context menus for different components.

Here is a simple example of a context menu set on the application:


Here is a short snippet from the above example showing you have to create a ContextMenu, hide the built-in menu items, and listen for menu events.
private function initContextMenu():void {
    // 1. Create the context menu if it doesn't exist
    // it will exist for the application, but won't for most other components
    if (!contextMenu) {
        this.contextMenu = new ContextMenu();
    }

    // 2. Hide the built-in menu items 
    // (you can't remove the basic 3 or 4 items like: Settings, About, etc)
    contextMenu.hideBuiltInItems();
    
    // 3. Add menu items, you can optionally set the menu item enablement and
    // visibility in the ContextMenuItem constructor
    var firstItem:ContextMenuItem  = new ContextMenuItem("Hello there!"true);
    contextMenu.customItems.push(firstItem);
    var secondItem:ContextMenuItem = new ContextMenuItem("Disabled");
    contextMenu.customItems.push(secondItem);
    var thirdItem:ContextMenuItem = new ContextMenuItem("Hidden");
    contextMenu.customItems.push(thirdItem);
    
    // 4. Listen for menu events
    // this event happens when the context menu is about to show
    contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, 
        function(event:ContextMenuEvent):void {
            // add logic here to determine the visibility or enablement
            secondItem.enabled = false;
            thirdItem.visible = false;
        });
    
    // 5. Handle menu item click events
    var handler:Function = function(event:ContextMenuEvent):void {
        Alert.show("You clicked on the menu item '" 
                    event.currentTarget.caption + "'");
    };
    firstItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handler);
    secondItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handler);
    thirdItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handler);
}

There are many restrictions to Flex ContextMenus, some of which will drive you crazy. Read carefully, it will save you time later.
  • Maximum of 15 custom menu items in the menu
  • No sub-menus allowed
  • No icons in menus
  • Menu items must be 100 characters or less
  • Control characters, newlines, and other white space characters are ignored
  • MANY reserved words including (but not limited to):
    • Save
    • Zoom In
    • Zoom Out
    • 100%
    • Show All
    • Quality
    • Play
    • Loop
    • Rewind
    • Forward
    • Back
    • Movie not loaded
    • About
    • Print
    • Show Redraw Regions
    • Debugger
    • Undo
    • Cut
    • Copy
    • Paste
    • Delete
    • Select All
    • Open
    • Open in new window
    • Copy link
    • Copy Link Location
    • Del
I'm not quite sure why there are so many restrictions, but I'm sure Adobe has a good reason for it!

More details about the restrictions can be found on the ContextMenuItem page.

There are a few other solutions for people who want more control over the menus. These usually involve adding right click listeners in JavaScript on top of the Flex application and passing that event into Flex to position and show a custom menu instead of the usual Flex context menu.
Here is one such solution: Custom Context Menu.
These solutions can work quite effectively, but since they depend on the browser they can be quite buggy.


7 comments:

Anonymous said...

Amen brother. Flex really does suck.

Not to mention, there is no "onRightClick" event, so you have to create a context menu to fudge listening for it. It's really screwed up.

Lets hope HTML5 kills off Flash in the (distant) future.

Anonymous said...

HTML5 still doesn't solve the problems of having to meet dependencies on browser implementations. Flex/Flash provides a very nice, programmatic solution to just that problem. So, I doubt it is dying anytime soon.

Though, I'm sure Steve Jobs wishes it would!

Susrut Mishra said...

Yes, I agree that flash player has got certain limitations but it has got the advantage of running in almost every kind of electronic device. Whether it is PC, Mac, Mobile flash is compatible with almost everything.

Anonymous said...

Nice article. Thanks.

Full list of reserved words:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/ui/ContextMenuItem.html

Prateek said...

Good blog. I am new to Flex and actionscript. I am trying to create a flex mobile appl that needs to display a external swf in an html page. When a user clicks on something on the swf a javascript function can be executed. I want to bring up a context menu using flex code when the javascript code is executed. Is it possible at all??

Chris Callendar said...

Hi Prateek,

There probably is a way to do that, but it's not something that I'm familiar with.

Chris

.Net Developers Offshore said...

Very fantastic and well-written post.Its extremely good and very helpful for me.Thanks for sharing this great post.