Tutorial: Context menus are our friends if we use them correctly
In my quest to blur the line between native apps and AIR apps, I decided to fully incorporate context menus (right-click) in the next release of DestroyTwitter. In my initial tests, I came to realize that the ContextMenu class is the roommate who is really nice and optimistic before you move in, then a nightmare to get along with once you’re finally settled. It screams to be extended, but ironically it’s a final class (not extendable). After a few hours, I found a solution. But first, the problem.
Let’s say I have 100 icons. I want each icon to have five actions accessible from its context menu. This results in 100 ContextMenu instances and 500 NativeMenuItem instances, as seen below:

This is not pretty. The solution: share. In programming, sharing is one big step towards drastically reducing memory usage. If I share a single context menu, I will have one instance instead of 100 and five item instances instead of 500.

As expected, memory usage is divided by 100. The problem with sharing the ContextMenu class using a display object’s contextMenu property is that it can’t be done. On paper it can be, but not the way you want. To share a context menu, you’d have to listen on Event.DISPLAYING and use the hitTest() method to check which object the user is right-clicking. From a developer’s standpoint, this is simply unethical. Also, Flash content doesn’t update the mouse position between sequential right-clicks, so you could have a major issue with power users.
The solution is to forget the ContextMenu class altogether. While you’re at it, forget the contextMenu property as well. If you want something done right, you have to do it yourself. Add a listener to the MouseEvent.RIGHT_CLICK event, share a single NativeMenu instance, and call the NativeMenu.display() method in the right-click handler. For the purpose of this demonstration, I construct the NativeMenu in the Icon class. Since we’d ideally share the menu, you’d construct it outside of the class that’s using it, then reference it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package { // import classes public class Icon extends Sprite { public var _menu:NativeMenu; public function Icon () { __construct (); __init (); } private function __construct ():void { _menu = new NativeMenu (); // construct NativeMenu items } private function __init ():void { addEventListener (MouseEvent.RIGHT_CLICK, __rightClick__, false, 0, true); } private function __rightClick__ ($event:MouseEvent):void { // change NativeMenu items' attributes _menu.display (stage, stage.mouseX, stage.mouseY); } } } |
There is a second chapter to the context menu nightmare, which is the API for managing items. It’s clumsy, excessive, and requires the developers to write some pretty gross-looking code. I’ll save the solution to that for another time.



