메뉴 : FlexNativeMenu

컴터/Flash & Flex 2008. 9. 3. 10:20

Creating a FlexNativeMenu control

You define a FlexNativeMenu control in MXML by using the <mx:FlexNativeMenu> tag. Specify an id value if you intend to refer to a component elsewhere in your MXML application, either in another tag or in an ActionScript block.

You specify the data for the FlexNativeMenu control by using the dataProvider property. The FlexNativeMenu control uses the same types of data providers as does the ManuBar control and the Menu control. Several of the XML attributes or object property names have meaning to the FlexNativeMenu control. For more information on structuring FlexNativeMenu data providers, see Defining FlexNativeMenu menu structure and data.

You can assign any name to node tags in the XML data. In subsequent examples, each node is named with the generic <menuitem> tag, but you can use <node>, <subNode>, <person>, <address>, and so on.

Contents

Creating an application or window menu

When you create an application or window menu using the FlexNativeMenu control, the top-level objects or nodes in the data provider correspond to the top-level menu items. In other words, they define the items that display in the menu bar itself. Items nested inside one of those top-level items define the items within the menu. Likewise, those menu items can contain items, in which case the menu item is a submenu. When the user selects the menu item it expands its own menu items. For example, the following screenshot displays a window menu with three menu items (plus an additional separator menu item). The item with the label "SubMenuItem A-3" in turn contains three menu items, so SubMenuItem A-3 is treated as a submenu. (The code to create this menu is provided later.)

For an MXML application using the Flex WindowedApplication container as the root MXML node, you can assign a FlexNativeMenu to the WindowedApplication instance's menu property. The menu is used as the application menu on OS X and the window menu of the initial window on Windows. Likewise, to specify a window menu for an additional window defined using the Flex Window container, assign a FlexNativeMenu to the Window instance's menu property. In that case the menu displays on Windows only and is ignored on OS X.

Note: Mac OS X defines a menu containing standard items for every application. Assigning a FlexNativeMenu object to the menu property of the WindowedApplication component replaces the standard menu rather than adding additional menus to it.

The following application defines a FlexNativeMenu as the menu property of a WindowedApplication container. Consequently, the specified menu is used as the application menu on OS X and the window menu of the initial window on Windows. This code creates the menu shown in the previous screenshot:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#ffffff" layout="absolute">
    <mx:menu>
        <mx:FlexNativeMenu dataProvider="{myMenuData}" 
            labelField="@label" 
            showRoot="false"/>
    </mx:menu>
    <mx:XML format="e4x" id="myMenuData">
        <root>
            <menuitem label="MenuItem A">
                <menuitem label="SubMenuItem A-1" type="check" toggled="true"/>
                <menuitem type="separator"/>     
                <menuitem label="SubMenuItem A-2"/>
                <menuitem label="SubMenuItem A-3">
                    <menuitem label="Sub-SubMenuItem A-3-1"/>
                    <menuitem label="Sub-SubMenuItem A-3-2" enabled="false"/>
                    <menuitem label="Sub-SubMenuItem A-3-3"/>
                </menuitem>
            </menuitem>
            <menuitem label="MenuItemB">
                <menuitem label="SubMenuItem B-1"/>
                <menuitem label="SubMenuItem B-2"/>
            </menuitem>
        </root>
    </mx:XML>
</mx:WindowedApplication>

Creating a context menu

Creating a context menu in a Flex AIR application involves two steps. You create the FlexNativeMenu instance that defines the menu structure. You then assign that menu as the context menu for its associated control. Because a context menu consists of a single menu, the top-level menu items serve as the items in the single menu. Any menu item that contains child menu items defines a submenu within the single context menu.

The FlexNativeMenu is a replacement for the context menu that you use with browser-based Flex applications (the flash.ui.ContextMenu class). You can use one type of menu or the other, but you can't specify both types for a single component.

To assign a FlexNativeMenu component as the context menu for a visual Flex control, call the FlexNativeMenu instance's setContextMenu() method, passing the visual control as the component parameter (the only parameter):

menu.setContextMenu(someComponent);

The same FlexNativeMenu can be used as the context menu for more than one object, by calling setContextMenu() multiple times using different component parameter values. You can also reverse the process (that is, remove an assigned context menu) using the unsetContextMenu() method.

The following example demonstrates creating a FlexNativeMenu component and setting it as the context menu for a Label control:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="absolute" 
    creationComplete="init();">
    
    <mx:Script>
        <![CDATA[
            import mx.controls.FlexNativeMenu;
            
            private var myMenu:FlexNativeMenu;
            
            private function init():void
            {
                myMenu = new FlexNativeMenu();
                myMenu.dataProvider = menuData;
                myMenu.labelField = "@label";
                myMenu.showRoot = false;
                myMenu.setContextMenu(lbl);
            }
        ]]>
    </mx:Script>
    
    <!-- The XML data provider -->
    <mx:XML format="e4x" id="menuData">
        <root>
            <menuitem label="MenuItem A"/>
            <menuitem label="MenuItem B"/>
            <menuitem label="MenuItem C"/>
        </root>
    </mx:XML>
    
    <mx:Label id="lbl" x="100" y="10" 
        text="Right-click here to open menu"/>
</mx:WindowedApplication>

In addition to context menus for visual components within an application window, an AIR application supports two other special context menus: dock icon menus (OS X) and system tray icon menus (Windows). To set either of these menus, you define the menu's structure using the FlexNativeMenu component, then you assign the FlexNativeMenu instance to the WindowedApplication container's dockIconMenu or systemTrayIconMenu property.

Before setting the dockIconMenu or systemTrayIconMenu property you may want to determine whether the user's operating system supports a dock icon or a system tray icon, using the NativeApplication class's static supportsDockIcon and supportsSystemTrayIcon properties. Doing so isn't necessary, but can be useful. For instance, you might want to customize a menu depending on whether it is used as the context menu for a dock icon or for a system tray icon.

Finally, while a dock icon exists automatically for an application, you must explicitly specify a system tray icon in order for the icon to appear. (Naturally, the icon must exist in order for the user to be able to right-click the icon to activate the context menu).

The following example defines a FlexNativeMenu that is used as a context menu. If the user's operating system supports a system tray icon, the code creates an icon and displays it in the system tray. The code then assigns the FlexNativeMenu instance as the context menu for the system tray and dock icon menus.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="vertical" 
    creationComplete="init();">
    
    <mx:Script>
        <![CDATA[
            import flash.desktop.DockIcon;
            import flash.desktop.InteractiveIcon;
            import flash.desktop.NativeApplication;
            import flash.desktop.SystemTrayIcon;
            import flash.display.Shape;
            import mx.controls.FlexNativeMenu;
            
            private var myMenu:FlexNativeMenu;
            
            private function init():void
            {
                // Create the menu
                myMenu = new FlexNativeMenu();
                myMenu.dataProvider = menuData;
                myMenu.labelField = "@label";
                myMenu.showRoot = false;
                
                var icon:InteractiveIcon;
                icon = NativeApplication.nativeApplication.icon;
                
                // If we need a system tray icon, create one and display it
                if (NativeApplication.supportsSystemTrayIcon)
                {
                    var iconData:BitmapData = createSystemTrayIcon();
                    SystemTrayIcon(icon).bitmaps = new Array(iconData);
                }
                
                // Use this approach if you want to assign the same menu
                // to the dock icon and system tray icon
                this.systemTrayIconMenu = this.dockIconMenu = myMenu;
                
                // Use this approach if you want to assign separate menus
//                if (NativeApplication.supportsDockIcon)
//                {
//                    this.dockIconMenu = myMenu;
//                }
//                else if (NativeApplication.supportsSystemTrayIcon)
//                {
//                    this.systemTrayIconMenu = myMenu;
//                }
            }
            
            private function createSystemTrayIcon():BitmapData
            {
                // Draw the icon in a Graphic
                var canvas:Shape = new Shape();
                canvas.graphics.beginFill(0xffff00);
                canvas.graphics.drawCircle(24, 24, 24);
                canvas.graphics.endFill();
                canvas.graphics.beginFill(0x000000);
                canvas.graphics.drawEllipse(13, 13, 9, 12);
                canvas.graphics.drawEllipse(27, 13, 9, 12);
                canvas.graphics.endFill();
                canvas.graphics.lineStyle(3, 0x000000);
                canvas.graphics.moveTo(11, 32);
                canvas.graphics.curveTo(24, 46, 37, 32);
                
                var result:BitmapData = new BitmapData(48, 48, true, 0x00000000);
                result.draw(canvas);
                
                return result;
            }
        ]]>
    </mx:Script>
    
    <!-- The XML data provider -->
    <mx:XML format="e4x" id="menuData">
        <root>
            <menuitem label="MenuItem A"/>
            <menuitem label="MenuItem B"/>
            <menuitem label="MenuItem C"/>
        </root>
    </mx:XML>
    
    <mx:Text text="Right-click on the dock icon (Mac OS X) or system tray icon (Windows)"/>
</mx:WindowedApplication>

Note: Mac OS X defines a standard menu for the application dock icon. When you assign a FlexNativeMenu as the dock icon's menu, the items in that menu are displayed above the standard items. You cannot remove, access, or modify the standard menu items.

Creating a pop-up menu

A pop-up menu is like a context menu, but the pop-up menu isn't necessarily associated with a particular Flex component. To open a pop-up menu, create a FlexNativeMenu instance and set its dataProvider property to populate the menu. To open the menu on the screen, call its display() method:

myMenu.display(this.stage, 10, 10);

The display() method has three required parameters: the Stage instance that defines the coordinates within which the menu is placed, the x coordinate where the menu is placed, and the y coordinate for the menu. For an example of using the display() method to create a pop-up menu, see Example: An Array FlexNativeMenu data provider.

One important thing to keep in mind is that the display() method operates immediately when it's called. Several property changes cause the FlexNativeMenu's data provider to invalidate (such as changes to the data provider, changing the labelField, and so forth). When the display() method is called immediately after making such changes, those changes aren't reflected in the menu that appears on the screen. For example, in the following code listing when the button is clicked no menu appears because the menu is created and the data provider is specified in the same block of code in which the display() method is called:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="absolute">
    
    <mx:Script>
        <![CDATA[
            import mx.controls.FlexNativeMenu;
            
            private function createAndShow():void
            {
                var myMenu:FlexNativeMenu = new FlexNativeMenu();
                myMenu.dataProvider = menuData;
                myMenu.labelField = "@label";
                myMenu.showRoot = false;
                // calling display() here has no result, because the data provider
                // has been set but the underlying NativeMenu hasn't been created yet.
                myMenu.display(this.stage, 10, 10);
            }
        ]]>
    </mx:Script>
    
    <!-- The XML data provider -->
    <mx:XML format="e4x" id="menuData">
        <root>
            <menuitem label="MenuItem A"/>
            <menuitem label="MenuItem B"/>
            <menuitem label="MenuItem C"/>
        </root>
    </mx:XML>
    
    <!-- Button control to create and open the menu. -->
    <mx:Button x="300" y="10" 
        label="Open Menu" 
        click="createAndShow();"/>
</mx:WindowedApplication>




<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute">
   
    <mx:Script>
        <![CDATA[
            import mx.events.FlexNativeMenuEvent;

            import mx.controls.FlexNativeMenu;
            import mx.events.FlexNativeMenuEvent;

            // The event listener that opens the menu with an XML data
            // provider and adds event listeners for the menu.
            private function createAndShow():void
            {
                ta1.text="";
                xmlBasedMenu.addEventListener(FlexNativeMenuEvent.ITEM_CLICK, menuShowInfo);
                xmlBasedMenu.addEventListener(FlexNativeMenuEvent.MENU_SHOW, menuShowInfo);
                xmlBasedMenu.display(stage, 225, 10);
            }

            // The event listener for the xml-based menu events.
            // Retain information on all events for a menu instance.
            private function menuShowInfo(event:FlexNativeMenuEvent):void
            {
                ta1.text = "event.type: " + event.type;
               
                // The label field is null for menuShow events.
                ta1.text += "\nevent.label: " + event.label;
               
                // The index value is -1 for menuShow events.
                ta1.text+="\nevent.index: " + event.index;
               
                // The item field is null for menuShow events.
                if (event.item != null)
                {
                    ta1.text += "\nItem label: " + event.item.@label
                    ta1.text += "\nItem toggled: " + event.item.@toggled;
                    ta1.text += "\nItem type: " + event.item.@type;
                }
            }

            // The event listener that creates an object-based menu
            // and adds event listeners for the menu.
            private function createAndShow2():void
            {
                ta1.text="";
                objectBasedMenu.addEventListener(FlexNativeMenuEvent.ITEM_CLICK, menuShowInfo2);
                objectBasedMenu.addEventListener(FlexNativeMenuEvent.MENU_SHOW, menuShowInfo2);
                objectBasedMenu.display(stage, 225, 10);
            }

            // The event listener for the object-based Menu events.
            private function menuShowInfo2(event:FlexNativeMenuEvent):void
            {
                ta1.text = "event.type: " + event.type;
               
                // The label field is null for menuShow events.
                ta1.text += "\nevent.label: " + event.label;
               
                // The index value is -1 for menuShow events.
                ta1.text += "\nevent.index: " + event.index;
               
                // The item field is null for menuShow events.
                if (event.item)
                {
                    ta1.text += "\nItem label: " + event.item.label
                    ta1.text += "\nItem toggled: " + event.item.toggled;
                    ta1.text += "\ntype: " + event.item.type;
                }
            }

            // The object-based data provider, an Array of objects.
            // Its contents are identical to that of the XML data provider.
            [Bindable]
            public var objMenuData:Array = [
                {label: "MenuItem A", children: [
                    {label: "SubMenuItem A-1", enabled: false},
                    {label: "SubMenuItem A-2"}
                ]},
                {label: "MenuItem B", type: "check", toggled: true},
                {label: "MenuItem C", type: "check", toggled: false},
                {type: "separator"},
                {label: "MenuItem D", children: [
                    {label: "SubMenuItem D-1"},
                    {label: "SubMenuItem D-2"},
                    {label: "SubMenuItem D-3"}
                ]}
            ];

        ]]>
    </mx:Script>

    <!-- The XML-based menu data provider.
    The <mx:XML tag requires a single root. -->
    <mx:XML id="xmlMenuData">
        <xmlRoot>
            <menuitem label="MenuItem A" >
                <menuitem label="SubMenuItem A-1" enabled="false"/>
                <menuitem label="SubMenuItem A-2"/>
            </menuitem>
            <menuitem label="MenuItem B" type="check" toggled="true"/>
            <menuitem label="MenuItem C" type="check" toggled="false"/>
            <menuitem type="separator"/>    
            <menuitem label="MenuItem D">
                <menuitem label="SubMenuItem D-1"/>
                <menuitem label="SubMenuItem D-2"/>
                <menuitem label="SubMenuItem D-3"/>
            </menuitem>
        </xmlRoot>
    </mx:XML>
   
    <mx:FlexNativeMenu id="xmlBasedMenu"
        showRoot="false"
        labelField="@label"
        dataProvider="{xmlMenuData}"/>
       
    <mx:FlexNativeMenu id="objectBasedMenu"
        dataProvider="{objMenuData}"/>

    <!-- Button controls to open the menus. -->
    <mx:Button x="10" y="5"
        label="Open XML Popup"
        click="createAndShow();"/>
    <mx:Button x="10" y="35"
        label="Open Object Popup"
        click="createAndShow2();"/>
    <!-- Text area to display the event information -->
    <mx:TextArea x="10" y="70"
        width="200" height="250"
        id="ta1"/>
</mx:WindowedApplication>
Trackbacks 0 : Comments 0

Write a comment