Wednesday, December 22, 2010

Drawing 3D Shapes in Flex

I found this great 3-part article by Lee Burrows on how to draw semi 3D shapes in Flex:
  • Part 1
  • Part 2
  • Part 3

  • I highly recommend that you check them out.

    Expanding on those examples I've changed them slightly in the following ways:
  • Instead of rotating the shape based on mouse position, the rotation now happens when you drag your mouse
  • Added a 3D Triangle and a 3D Arrow (combines a triangle and a cube)
  • Added a 3D shape with 6 different hockey logos, one on each side


  • All credit goes to Lee for his excellent examples. If you want to understand the math behind it all, then definitely read his article. My examples don't have much in the way of comments.

    View Source is available for all the following examples, right click below to access the source.

    Example #1 - Simple Rotating Cube:


    Example #2 - Rotating Triangle:


    Example #3 - Rotating Arrow (with highlighting):


    Example #4 - Cube With Image/Bitmap Fill:

    You might notice a few tiny problems with the arrow. When rotating it in certain directions some lines show through that shouldn't be visible. It is most likely due to combining the two shapes (one cube and one triangle) to form the arrow.

    Also, the mouse dragging to rotate works as expected until you've rotated the shape 180 degrees, then it becomes backwards. I haven't spent the time to try and fix this.

    The fourth example uses Lee's Shape3D class which encapsulates the 3D functionality in one simple class. It is much cleaner this way.

    Thursday, November 25, 2010

    YouTube Videos in Flex

    Here is an example of how to get YouTube videos to be shown inside your Flex Application.

    The first thing to do is add an SWFLoader to your mxml file. The source property of the SWFLoader gets set to the url of the video that you want to show inside Flex.
    But you can't just use any YouTube url like this one:
    http://www.youtube.com/watch?v=owGykVbfgUE
    Instead you use a url in this form:
    http://www.youtube.com/v/VIDEO_ID?version=3

    The id of the video you want to play (e.g. owGykVbfgUE) must replace the VIDEO_ID portion of the url. This url actually redirects to an SWF file somewhere.

    The version=3 parameter is very important. This tells YouTube to load the ActionScript 3.0 version of the SWF file. Without this parameter it defaults to the AS2 version which doesn't not play nicely with AS3. I found that I could watch one video, but after that no other videos could be played (I found this blog post that explains why if you're interested). I also found this YouTube reference which is where I learned about using the version=3 parameter.

    There are a few other parameters that you can use like:
    • autoplay=1 - starts the video immediately without the user having to press play
    • fs=1 - allows full screen
    • rel=1 - shows related content after the video has finished playing
    For a full list of the parameters go here

    And finally, when you want to play another video, make sure you call the swfLoader.unloadAndStop() function otherwise you can get multiple videos playing at the same time, very confusing.

    Keep in mind that when you run this locally you will see a lot of SecurityExceptions in your console, this is expected and normal.

    And one last thing, some videos you will not be able to play inside Flex due to copyright restrictions. The owners of youtube videos must be able to specify whether the video can be played from a different website using an embedded player.

    Here is the example in action (right click to view-source):

    Wednesday, October 27, 2010

    Displaying Html text in Labels

    Displaying html content inside Flex labels is not as straight forward as it was in Flex 3 by simply setting the htmlText property. Here are the 3 Spark controls used for displaying text:
    • Label - lightweight plain text only
    • RichText - as the name says it provides support for rich text.
      Also allows html content to be imported (anchor tags <a> don't work)
    • RichEditableText - provides the same rich text support as the RichText control.
      Allows editing and anchor html tags work properly
    Here is a list of the supported HTML tags: <div>, <p>, <a>, <span>, <img>, <br>.

    As noted above, if you want to use anchor <a> tags, you must use a RichEditableText control. In this case you'd most likely want to also set the editable="false" property.
    The anchor href property can be set to a relative path like
    <a href="index.html">index</a>
    Or an absolute one like
    <a href="http://google.com" target="_blank">google</a>
    Note that you can set the target property to control whether the link is opened in a new window or not.
    If you want to listen for when the user clicks on an anchor it is possible, but involves a lot more work. Basically you import the html string into a TextFlow object. Then you iterate through all the child elements until you find the LinkElement (which represents the anchor tag), and then add a FlowElementMouseEvent.CLICK event listener.

    Here is some sample code that I use to achieve this:
    /**
     * Converts the html string (from the resources) into a TextFlow object
     * using the TextConverter class. Then it iterates through all the 
     * elements in the TextFlow until it finds a LinkElement, and adds a 
     * FlowElementMouseEvent.CLICK event handler to that Link Element.
     */
    public static function addLinkClickHandler(html:String, 
            linkClickedHandler:Function):TextFlow {
      var textFlow:TextFlow = TextConverter.importToFlow(html, 
        TextConverter.TEXT_FIELD_HTML_FORMAT);
      var link:LinkElement = findLinkElement(textFlow);
      if (link != null) {
        link.addEventListener(FlowElementMouseEvent.CLICK, 
              linkClickedHandler, false0true);
      else {
        trace("Warning - couldn't find link tag in: " + html);
      }
      return textFlow;
    }

    /**
     * Finds the first LinkElement recursively and returns it.
     */
    private static function findLinkElement(group:FlowGroupElement):LinkElement {
      var childGroups:Array = [];
      // First check all the child elements of the current group,
      // Also save any children that are FlowGroupElement
      for (var i:int = 0; i < group.numChildren; i++) {
        var element:FlowElement = group.getChildAt(i);
        if (element is LinkElement) {
          return (element as LinkElement);
        else if (element is FlowGroupElement) {
          childGroups.push(element);
        }
      }
      // Recursively check the child FlowGroupElements now
      for (i = 0; i < childGroups.length; i++) {
        var childGroup:FlowGroupElement = childGroups[i];
        var link:LinkElement = findLinkElement(childGroup);
        if (link != null) {
          return link;
        }
      }
      return null;
    }

    A simple control that I've created and use frequently is called HtmlLabel which extends the RichEditableText class to provide simple support for html text:
    <?xml version="1.0" encoding="utf-8"?>
    <s:RichEditableText xmlns:fx="http://ns.adobe.com/mxml/2009"
      xmlns:s="library://ns.adobe.com/flex/spark"
      xmlns:mx="library://ns.adobe.com/flex/mx"
      focusEnabled="false"
      selectable="false"
      editable="false">

      <fx:Script>
        <![CDATA[
          import flashx.textLayout.conversion.TextConverter;

          override public function set text(value:String):void {
            super.textFlow = TextConverter.importToFlow(value, 
              TextConverter.TEXT_FIELD_HTML_FORMAT);
          }
        ]]>
      </fx:Script>

    </s:RichEditableText>

    Spell Checking

    Here is a short example of how to get the Adobe Squiggly spell checking tool installed. Squiggly can be downloaded here.

    Squiggly files:
    • AdobeSpellingConfig.xml - put this file in your project's src folder. It defines the locations of the dictionaries and which language(s) to use.
    • en_US.aff, en_US.dic - these are the dictionary files. You'll need different ones for different languages of course. By default they go in the src/dictionaries/en_US folder.
    • AdobeSpellingEngine.swc - the main engine library - required, goes in project lib folder.
    • AdobeSpellingUI.swc - the ui library for Flex 3/MX components (e.g. <mx:TextArea>)
    • AdobeSpellingUIEx.swc - the ui library for Flex 4/Spark components (e.g. <s:TextArea>)
    ** Only use one of AdobeSpellingUI.swc or AdobeSpellingUIEx.swc.

    To integrate Spell Checking into a Spark TextArea (id="textArea"), all you have to do is add one line:

    SpellUI.enableSpelling(textArea, "en_US");

    I did notice one problem with using Squiggly with Spark controls. The default Cut/Copy/Paste/Select All context menu items were not available anymore. I found a workaround for this by getting the contextMenu (which gets set on the RichEditableText control, not the TextArea) and setting clipboardMenu = true. See the example below for more details (right click to View Source).

    Squiggly is still in prerelease, so a few bugs are expected. There is a forum here for discussions on Squiggly, and to report problems.

    Thursday, September 9, 2010

    Flex 4 Tree Lines

    I've updated my previous blog post on Tree Lines to include a Flex 4/Spark version which uses the MXTreeItemRenderer class.

    For more documentation on how to use it see the blog post linked above.


    I've also updated the AdvancedDataGrid example to show tree lines in the tree:

    Friday, August 27, 2010

    Detecting browser height

    Here is an example of one way to find out the height of the browser window from inside Flex. It is very easy to find this out if your have your Flex application set to height="100%". But if you use a fixed height like height="300" then stage.stageHeight and app.height both return 300.

    This example uses the ExternalInterface to determine the height of the browser by calling the eval javascript function (it is a built-in function).

    E.g.
    var browserHeight:Number = ExternalInterface.call("eval", "window.innerHeight");

    Different browsers (NS, FF, Chrome, IE, Safari) obviously don't all support this call. So far the window.innerHeight property works on all of them except IE. For IE you can use this one (IE 7 and above I think?):
    var browserHeight:Number = ExternalInterface.call("eval", "document.documentElement.clientHeight");

    And if your browser is older you can try this one:
    var browserHeight:Number = ExternalInterface.call("eval", "document.getElementsByTagName('body')[0].clientHeight");

    Browsers will also handle errors differently, so if you try to use one of those JavaScript functions in one browser you might get undefined return, and in another browser you might get an error dialog box.

    Here is an example of this in action, it opens in a new browser window to show it properly.
    If it was embedded on this page using an <iframe> tag then the size returned is that of the iframe, not the browser.

    - Browser Height Example -
    Click this image to open the real application


    Obviously if you were interested in the browser width then you could do exactly the same thing but replace innerHeight with innerWidth and clientHeight with clientWidth.

    Comments welcome.

    Wednesday, August 11, 2010

    Synchronized Scrollbars

    I recently had a need for two side-by-side TextAreas whose vertical scrollbars were synchronized. So if you drag the left scrollbar, the right one updates, and vice versa.

    I've written a utility class called LinkedScrollers that synchronizes the scrolling of two Scrollers. It has 5 public properties:
    • enabled (defaults to true) - set to false to allow scrollbars to move independently
    • scroller1 - the first Scroller
    • scroller2 - the second Scroller
    • component1 - the first SkinnableComponent, e.g. List, TextArea
    • component2 - the second SkinnableComponent (List, TextArea, etc)
    Originally I wanted to bind the scrollers directly to my LinkedScrollers in MXML like this:
    <spark:LinkedScrollers scroller1="{list.scroller}" scroller2="{textArea.scroller}"/>
    But unfortunately the scroller property on List/TextArea is not bindable, so that didn't work. You can still use the scroller1 and scroller2 in ActionScript (e.g. in the application's creationComplete handler) to set the scrollers.

    So another solution is to set the component1 and component2 properties to the two SkinnableComponents that you want to link (Lists, TextAreas, etc). It should work for any SkinnableComponent that contains a "scroller" skin part.
    E.g.
    <spark:LinkedScrollers component1="{list}" component2="{textArea}"/>

    Here it is in action, view source enabled (right click on the example below):


    As you might guess, this follows on from my previous post on Spark TextArea With Line Numbers.

    Friday, July 16, 2010

    Spark TextArea with Line Numbers

    Here is a skin that you can use on the Spark TextArea class to show line numbers down the left side of the text.
    The line numbers use the same size font as the TextArea.

    It is very simply to use, simply set the skinClass property in mxml like this:
    <s:TextArea skinClass="flex.utils.spark.TextAreaLineNumbersSkin"/>

    If you want a horizontal scroll bar on the TextArea, then set lineBreak="explicit" and the horizontal scrollbar will appear.

    Here is an example of it in action (right click to view source).


    It would be very easy to modify this skin to make it resizable by adding a resize handle in the bottom right corner. Look at the source code from my previous blog post on Resizable Controls, specifically the flex.utils.spark.resize.ResizableTextAreaSkin class, it uses a custom skin for the Scroller, which adds the resize handle.

    Monday, June 28, 2010

    Flex 4 Spark Resizable Controls

    Please go here for Flex 3 Resizable Containers.

    I've created a bunch of skins for many of the common Spark components that allows them to be resized. Each of these skins contains a resizeHandle that when dragged allows the control to be resized. There are two resize handle classes that you can use, the default is called flex.utils.spark.resize.ResizeHandleLines. You can replace every occurrence of that class with flex.utils.spark.resize.ResizeHandleDots if you prefer.

    Here are a list of resize skins:

    With the exception of the ResizableLabel class, all the others are Skins, and as such can be used very simply by setting the skinClass="flex.utils.spark.resize.___Skin" property to the appropriate skin.

    Another option is to create a CSS style for ALL spark.components.Scroller classes to use the flex.utils.spark.resize.ResizableScrollerSkin class like this:
    <fx:Style>
    @namespace "library://ns.adobe.com/flex/spark";
    @namespace mx "library://ns.adobe.com/flex/mx";
    @namespace spark "flex.utils.spark.*";
    @namespace resize "flex.utils.spark.resize.*";

    /* Make all Scroller's use the resizable scroller skin. */
    s|Scroller {
      skin-class: ClassReference("flex.utils.spark.resize.ResizableScrollerSkin");

    </fx:Style>

    ** Note that I've renamed the Flex3 package flex.utils.ui.resize.* to the new Flex4/Spark package name flex.utils.spark.resize.*.

    The most used skin is the ResizableScrollerSkin, it is used on TextAreas, Lists, DataGrids, Trees, ComboBoxes, DropDownLists, and anything else that uses a Scroller component. The way it works is to use a skin for the Scroller that adds the resize handle and uses custom HScrollBar and VScrollBar classes which leave room for the resize handle (the simplest way I could think to do it). Each of the resizable skins uses the ResizeManager class to handle the mouse events and resize the appropriate control.

    The resizable ComboBox and DropDownList skins are slightly different in that they both save the size of the drop down list since it gets destroyed and re-created each time. It also sets the popUpWidthMatchesAnchorWidth="false" after resizing since the width no longer matches the anchor.

    I've also added support for restricting the resize in only the vertical or horizontal direction. There are many ways you can do this, you can either set a style on the resize component:
    .resizePanel {
      resize-direction: vertical; /* or horizontal */
    }
    Or you can call a static method on the ResizeManager class:
    ResizeManager.setResizeDirection(resizePanel, "vertical"); // or "horizontal"
    Or if you can access the ResizeManager class (usually stored in the skin class), then you can set the resizeDirection property on the manager like this:
    resizeManager.resizeDirection = "vertical"; // or "horizontal";
    There are constants defined in the ResizeManager class for "vertical", "horizontal", and "both" (default).

    September 30th, 2010 Update:
    I've added a new skin called ResizableDraggableTitleWindowSkin that uses the MoveManager class to allow dragging the TitleWindow around the screen. It also adds a small drag handle in the titlebar too.
    The same could be done for other classes (e.g. Panel) by following the same procedure. All that is required is a dragComponent (the component that listens for mouse drag events) and a moveComponent (the component that gets moved - in this case it is the TitleWindow).

    Here is an example of most of the skins, view-source enabled.

    Tuesday, June 1, 2010

    TitledBorderBox (Flex 4/Spark)

    I've re-written my original TitledBorderBox class (Flex 3) to use Spark/Flex 4 components. It is slightly simpler, and hopefully more lightweight. It extends the SkinnableContainer class, and uses it's own skin (flex.utils.ui.TitledBorderBoxSkin).

    Here are the properties on the component:
    • backgroundAlpha - the background alpha for the box (default: 1)
    • backgroundColor - the background color for the box (default: white)
    • backgroundVisible - if the background should be shown (default: true)
    • borderAlpha - the border alpha for the box (default: 1)
    • borderColor - the border color for the box (default: black)
    • borderWeight - the thickness of the border (default: 1)
    • borderVisible - if the border should be shown (default: true)
    • cornerRadius - the corner radius for rounded corners (default: 0)
    • dropShadowVisible - if a drop shadow is shown (default: false)
    • titleStyleName - the style name for the title label (default "windowStyles")
    • title - the title to show in the border
    It also supports most of the layout properties too as styles (paddingLeft/Right/Top/Bottom, gap/horizontalGap/verticalGap, horizontal/verticalAlign, etc) for convenience.

    The way the border is drawn is to simply draw a line over top of the border, but underneath the title that is the same color as the background. If you set borderVisible="false", then it will attempt to find the background color of the parent and use that instead.

    Here it is in action (view source enabled, right click):

    Friday, May 14, 2010

    Highlight The ScrollBar Track

    I'm not sure what this feature is called, but have you seen in Google Chrome when you search the current web page for a certain phrase, the vertical scroll bar will be highlighted showing you all the locations of that phrase? See the screenshot on the right for an example of what I mean.  In front of the track, but behind the scrollbar thumb are lines showing you were the search results are located. It's a nice little feature that I find quite helpful.

    I've implemented the same thing in Flex for showing the scrollbar track highlighting when words in a TextArea are highlighted, and when items are selected in a List (it should work for a DataGrid too, but I haven't tested it).

    The nice thing about my implementation is that it is very simple to set up.  All you have to do is set the verticalScrollBarStyleName property on your List, DataGrid or TextArea, and then create your CSS to set the trackSkin style to one of my two custom skins and it will all work.
    E.g.
    <mx:Style>
    .highlightList {
        track-skin: ClassReference("skins.HighlightListScrollTrackSkin");
    }
    .highlightTextArea {
        trackSkin: ClassReference("skins.HighlightTextAreaScrollTrackSkin");
    }
    </mx:Style>

    <mx:List verticalScrollBarStyleName="highlightList"/>

    The text highlighting in the TextArea is done using some useful code that I found on this blog:
    How to Highlight the Text in Flex.
    I slightly modified the com.components.BlockTextArea class to make it work with my skins.HighlightTextAreaScrollTrackSkin class.

    Here's the example (right click to View Source):


    You can also set two more styles if you want to customize the color and alpha transparency of the highlighting:
    highlight-color and highlight-alpha. Just add it to the css classes shown above.

    Wednesday, April 21, 2010

    Prompting Controls (Spark/Flex 4)

    Here are a few useful controls written in Flex 4 for displaying prompt text, and for showing an icon in a button.

    The IconButton class extends the defaults Flex 4 Button class, and adds the icon style as well as the labelPlacement (left, right, top, bottom) and paddingLeft, paddingTop, paddingRight, and paddingBottom styles.

    I also made a simple extension of the TextInput class which shows a prompt text when the text input is empty and not in focus, it is called PromptingTextInput.

    The third example is called ClearTextInput, it extends PromptingTextInput to show a small clear button (which is a IconButton) on the right hand side of the text input whenever there is text inside the text input.

    The fourth example is what I call a PromptingList. It shows a prompt text whenever the list is empty. This is useful if you have a list that gets populated from a remote service (e.g "Loading..."), or if your list gets items added to it by the user, or by dragging items into the list (as in the example below).

    Each of the prompting controls supports a style called promptStyleName which lets you set the styleName for the prompt Label.

    ** Note that the package structure has been renamed to flex.utils.spark.* for all Spark controls.

    Here it is:

    Tuesday, April 20, 2010

    Divider Background Color

    Here is a simple component that extends the Flex 3 mx.containers.DividedBox class to provide two styles for filling in the background behind each divider.

    My component is creatively called flex.utils.ui.DividedBox. It has all the same properties and styles as its parent, plus these two styles:
    • dividerBackgroundColor - the background color behind each divider, defaults to #000000.
    • dividerBackgroundAlpha - the alpha value for the background color, defaults to 1.

    Here it is in action (View Source enabled):

    Wednesday, March 31, 2010

    Tree Item ToolTips

    Here is how you can set custom tooltips in Flex 3 on each item in a Tree.

    First, you have to set the following properties on the Tree:
    • showDataTips="true" - causes tooltips to be shown
    • dataTipFunction="myDataTipFunction" - sets the function which returns the tooltip for each item
    • itemRenderer="ToolTipItemRenderer" - tells the tree to use our custom renderer (which extends the default TreeItemRenderer)
    The itemRenderer isn't necessary unless you want to have control over where the tooltip is positioned (see below).

    Also note that if you set the dataTipField property on the tree instead of the dataTipFunction then your tooltips will only show up when the tree item isn't fully visible due to scrollbars. By setting the dataTipFunction it forces the tooltips to always show when the mouse is over the tree node.

    Now, on to the next problem. By using the method above the tooltips are always displayed. But the default position for the tooltip is right on top of the tree node, which is annoying. So this is why we use our own custom item renderer so that we can position the tooltip below or above the node (or anywhere you want it).

    Here is an example with View Source enabled:

    Wednesday, March 17, 2010

    Custom Components Live Preview (Design Mode)

    If you have created your own component and you drag it onto your Flex app in Design Mode and it appears as a tiny almost invisible square on your screen, then watch the video below to see how you can get it working properly (like the default controls do).

    I found this awesome video tutorial on YouTube that explains how you can create what is called a Live Preview of your component so that your custom component actually appears with the right appearance and dimensions.



    Be sure to check out the author's blog at blog.flashgen.com.

    The end result that I learned from this video is that if you have a Flex Project which contains your custom component, and you try to use it in an MXML file then it won't work properly. If the custom component is in a separate Flex Library Project (or SWC) then it will work properly.

    Thursday, March 4, 2010

    DragHandle, ResizeHandle

    Here are two customizable drag and resize handles:


    You can set the following properties:
    • rows - sets the number of rows of dots
    • columns - sets the number of columns of dots
    • dotSize - sets the dot size (defaults to 2)
    • dropShadowEnabled - sets whether a drop shadow is used (defaults to false)
    • dropShadowColor - sets the drop shadow color
    • keepOnTop - if true then the handle will be on top of the other sibling components
    • positionResizeHandle - If true then the resize handle will be positioned in the bottom right corner of the parent (ResizeHandle only)
    * Note: if you explicitly set the width and height of the DragHandle or ResizeHandle, then the rows and columns properties are ignored. In this case as many dots are rendered as will fit into that area.

    You can set the following styles too:
    • backgroundColor, backgroundAlpha - sets the background color alpha for the drag/resize handle
    • dragHandleColor, dragHandleAlpha - sets the color and alpha value for the drag handle
    • resizeHandleColor, resizeHandleAlpha - sets the color and alpha value for the resize handle

    These two components are used in all the Resizable Containers.

    Thursday, February 4, 2010

    Image CheckBox and RadioButton

    Here are two custom components that extend the CheckBox and RadioButton classes to render an image in between the checkbox/radiobutton icon and label.

    The main property to set is imageSource which acts just like the Image.source property.

    The image position depends on the labelPlacement property (left, right, top, bottom) and the horizontalGap style.

    You can also set the imageWidth and imageHeight properties to scale the image down. If you only set one of those properties then the other one is calculated to keep the image's width and height ratio the same.


    Note that the ImageCheckBox actually extends my flex.utils.ui.CheckBox class and not the expected mx.controls.CheckBox class.

    The flex.utils.ui.CheckBox class supports backgroundColor and backgroundAlpha styles, and as a result the background is always painted. But the default alpha value is 0, so usually you won't see the background unless you set the background color and alpha. The reason for this is that the default mx.controls.CheckBox class has a gap between the checkbox icon and the label (which is the horizontalGap style). This gap causes mouse out events to fire when your cursor moves from the icon or label into this gap. As a result the checkbox tooltip will disappear, and the checkbox will not have the rollover styles. So by painting an invisible background color over the whole area of the checkbox this problem doesn't occur. Same thing applies with the RadioButton class.

    Friday, January 29, 2010

    Drawing Dashed Lines, Arcs, and Cubic Curves

    The ActionScript Graphics class supports drawing solid lines and quadratic curves. But there isn't native support for dashed lines or cubic (Bezier) curves.

    I've created a sample application that shows the three line types: straight, quadratic curve and cubic curve. It also lets you choose between showing a solid line, a dashed line, or both. The line thickness can also be adjusted.



    I also got a little carried away and added the quadratic and cubic control points as buttons that you can drag around the canvas to change the curve.

    Most of the drawing functionality for these examples is in the GraphicsUtils.as class that contains the following static functions:
    • drawLine() - draws a straight line, either solid (using Graphics.lineTo() function) or dashed
    • drawQuadCurve() - draws a quadratic curve, either solid (using Graphics.curveTo() function) or dashed
    • drawCubicCurve() - draws a cubic curve (two control points), either solid or dashed. The curve is an approximation done by dividing the curve into many small segments and drawing straight lines
    • drawCircle() - draws a circle, either solid (using Graphics. drawCircle() function) or dashed
    • drawArc() - draws an arc, either solid or dashed
    The dashed lines are drawn by dividing the line into many small segments to draw the dashes. By default a dash length of 10 pixels is used, but that is customizable.

    The equations used to calculate the values at any point along the line for the three cases were found on the Wikipedia entry for B├ęzier curves.

    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.