开发者

Flex Menu shortcut keys and custom renderer

I need to create a menu component in which each menu item looks like this:

icon label right-aligned-keyboard-shortcut

I tried creating a custom menu item renderer, but a) keyboard shortcuts are not right aligned b) there are a lot of issues with sub menus.

I also tried using data grids and panels and a mixture thereof to draw this kind of menu but it is too messed up.

Any pointers on how I can achieve this?

EDIT: Adding source code

Main.mxml

<mx:Style source="assets/main.css" />

<mx:Script>
    <![CDATA[
        import FlyOutMenuItem;
        import FlyOutMenuRenderer;
        import com.jusfortechies.controls.CustomMenuItemRenderer;
        import com.jusfortechies.controls.ValueObject;

        import mx.collections.ArrayCollection;
        impo开发者_C百科rt mx.controls.Menu;
        import mx.events.CollectionEvent;
        import mx.events.MenuEvent;

        [Bindable]
        private var myMenuData:ArrayCollection = new ArrayCollection();

        [Bindable]
        private var mainMenuData:ArrayCollection = new ArrayCollection();

        [Bindable]
        [Embed(source="Button.png")]
        public var Button:Class;

        [Bindable]
        public var state:Boolean = false;

        [Bindable]
        private var myMenu:Menu;

        [Bindable]
        private var mainMenu:Menu;

        // Create and display the Menu control.
        private function createAndShow():void {

            mainMenu = Menu.createMenu(null, mainMenuData, false);
            mainMenu.labelField="label";

            //myMenu.itemRenderer = new ClassFactory(CustomMenuItemRenderer);
            mainMenu.itemRenderer = new ClassFactory(FlyOutMenuRenderer);

            mainMenu.addEventListener(KeyboardEvent.KEY_DOWN,handleFlyOutMenuKeyStroke);
            mainMenu.addEventListener(KeyboardEvent.KEY_UP,handleFlyOutMenuKeyStrokeUp);
            mainMenu.addEventListener(MenuEvent.ITEM_CLICK,handleFlyOutMenuHandleClick);

            myMenu = Menu.createMenu(mainMenu, myMenuData, false);
            myMenu.labelField="label";

            //myMenu.itemRenderer = new ClassFactory(CustomMenuItemRenderer);
            myMenu.itemRenderer = new ClassFactory(FlyOutMenuRenderer);

            myMenu.addEventListener(KeyboardEvent.KEY_DOWN,handleFlyOutMenuKeyStroke);
            myMenu.addEventListener(KeyboardEvent.KEY_UP,handleFlyOutMenuKeyStrokeUp);
            myMenu.addEventListener(MenuEvent.ITEM_CLICK,handleFlyOutMenuHandleClick);

            mainMenu.addChild(myMenu);

            //Position the menu and show it when the button is clicked
            mainMenu.show((this.width/2 - this.myButton.width/2), 50);
        }

        protected function handleFlyOutMenuKeyStrokeUp(event:KeyboardEvent):void { 
            state = false;
        }

        protected function handleFlyOutMenuKeyStroke(event:KeyboardEvent):void {
            trace("target:"+event.currentTarget+"state:"+state+";keycode:"+event.keyCode);

            // tried to check for keycode's like 2, 3 which correspond to ctrl+b and ctrl+c respectively
            // did not work. Hence go for state based individual key check

            if(event.keyCode == Keyboard.ESCAPE && myMenu.visible) {
                myMenu.hide();
            } else if (state) {
                if (event.keyCode >=65 && event.keyCode <= 90) { // check if any alphabet was pressed after control key
                    // A ascii code = 65. But in our data array, A starts at 1 NOT 0. So we detect 65-1 = 64
                    trace("Inside handleFlyOutMenuKeyStroke"+event.keyCode);
                }
            } else if(event.keyCode == Keyboard.CONTROL){
                state = true;
                return;
            }
            state=false;

            if(myMenu.visible) {
                myMenu.hide();
            }
        }

        protected function handleFlyOutMenuHandleClick(event:MenuEvent):void
        {
            if(event.currentTarget == mainMenu){
                trace('MainMenu HandleClick');
                myMenu.show((mainMenu.x + mainMenu.width), (mainMenu.y + mainMenu.height/2));
                //myMenu.show((this.width/2 - this.myButton.width/2), 50);
            }
            trace("Inside MenuHandleClick");
        }



        public function init():void {
            /*mainMenuData.addItem(new ValueObject("MA", "MenuItem A", "menuOddItem"));
            mainMenuData.addItem(new ValueObject("MB", "MenuItem B", "menuEvenItem"));
            mainMenuData.addItem(new ValueObject("MC", "MenuItem C", "menuOddItem"));
            mainMenuData.addItem(new ValueObject("MD", "MenuItem D", "menuEvenItem"));*/

            myMenuData.addItem(new FlyOutMenuItem("Item A", "A", "Button"));
            myMenuData.addItem(new FlyOutMenuItem("Item B", "B", "Button"));
            myMenuData.addItem(new FlyOutMenuItem("Item CM", "C", "Button"));
            myMenuData.addItem(new FlyOutMenuItem("Item DE", "D", "Button"));
        }
    ]]>
</mx:Script>

<mx:VBox>
    <!-- Define a Button control to open the menu -->
    <mx:Button id="myButton" initialize="init()" label="Open Menu" click="createAndShow();"/>
</mx:VBox>

FlyOutMenuItem.as

package { [Bindable] public class FlyOutMenuItem { public var label:String; public var shortCut:String; public var icon:String;

    public function FlyOutMenuItem(label:String, shortcut:String, icon:String)
    {
        this.label = label + "  Ctrl+"+shortcut;
        this.shortCut = shortcut;
        this.icon = icon;
    }
}

}

FlyOutMenuRenderer.as

package { import mx.controls.Label; import mx.controls.menuClasses.MenuItemRenderer;

import spark.components.Label;

[Bindable]
public class FlyOutMenuRenderer extends MenuItemRenderer
{
    override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {

        //Get the style name from Menu VO and set to the menu item  
        //this.styleName = ValueObject(this.data).styleName;

        this.label.ignorePadding = true;
        trace("Style.align.MenuRenderer.label:"+this.label.getStyle("textAlign"));

        super.updateDisplayList(unscaledWidth, unscaledHeight);
    }

    public function FlyOutMenuRenderer()
    {
        super();
    }
}

}

CustomMenuItemRenderer.as /*from justfortechies.com */

package com.jusfortechies.controls { import mx.controls.menuClasses.MenuItemRenderer;

[Bindable]
public class CustomMenuItemRenderer extends MenuItemRenderer
{
    override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {

        //Get the style name from Menu VO and set to the menu item  
        this.styleName = ValueObject(this.data).styleName;

        super.updateDisplayList(unscaledWidth, unscaledHeight);
    }
}

}

ValueObject.as /*from justfortechies.com */

package com.jusfortechies.controls { [Bindable] public class ValueObject { public var id:String; public var label:String; public var styleName:String;

    public function ValueObject(id:String, label:String, styleName:String)
    {
        this.id = id;
        this.label = label;
        this.styleName = styleName;
    }

}

}


This is my source code for the MenuBar experiment intending to the same thing - use a custom renderer to display a different type of menu.

P.S.: This is NOT the answer to this question. This post was created to separate the two approaches that I have taken.

FlyOutMenuItem.as

package
{
    import mx.controls.Menu;

    [Bindable]
    public class FlyOutMenuItem extends Menu
    {
        public var label:String;
        public var shortCut:String;
        public var icon:String;

        public function FlyOutMenuItem(label:String, shortcut:String, icon:String)
        {
            this.label = label + "  Ctrl+"+shortcut;
            trace("Creating new Flyoutmenuitem with label:"+this.label);
            this.shortCut = shortcut;
            this.icon = icon;
        }
    }
}

FlyoutMenuBar.as

package
{
    import mx.controls.Menu;
    import mx.controls.MenuBar;
    import mx.core.ClassFactory;

    [Bindable]
    public class FlyoutMenuBar extends MenuBar
    {
        public function FlyoutMenuBar()
        {
            super();
        }

        override public function getMenuAt( index:int ) : Menu     
        { 
            var menu:Menu = super.getMenuAt( index );
            //menu.styleName = "myMenuItemRendererStyleName";
            menu.itemRenderer = new ClassFactory( FlyoutMenuItemRenderer );

            return menu;
        }
    }
}

FlyoutMenuItemRenderer.as

package
{
    import mx.controls.Alert;
    import mx.controls.menuClasses.MenuItemRenderer;
    import mx.core.IFlexDisplayObject;

    [Bindable]
    public class FlyoutMenuItemRenderer extends MenuItemRenderer
    {
        public function FlyoutMenuItemRenderer()
        {
            super();
        }

        [Embed(source="Button.png")]
        public var Button:Class;

        override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {
            trace("MenuRenderer.label:"+this.label.text+"; id:"+this.id);
            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }
    }
}

Main.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       xmlns:renderers="*">
    <fx:Script>
        <![CDATA[
            import FlyOutMenuItem;

            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            import mx.controls.Menu;
            import mx.controls.menuClasses.MenuBarItem;
            import mx.events.FlexEvent;

            [Bindable]
            private var menuBarData:ArrayCollection = new ArrayCollection();

            protected function flyoutMenuBar_creationCompleteHandler(event:FlexEvent):void
            {
                //var numMenus:int = flyoutMenuBar.menus.length;
                //var numChild:int = flyoutMenuBar.numChildren;
                //Alert.show("numMenus:"+numMenus+"; numChild:"+numChild, "CreationComplete");

                flyoutMenuBar.addChild(new FlyOutMenuItem("Item A", "A", "Button"));
                var child:Menu = flyoutMenuBar.getMenuAt(0);
            }

        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
        <fx:XML id="mainMenuBarButtonData">
            <root>
                <menuitem label="Flyout Menu">
                    <menuitem label="ABC"/>
                    <menuitem label="DEF">
                        <menuitem label="GHI" />
                    </menuitem>
                </menuitem>
            </root>
        </fx:XML>
    </fx:Declarations>
    <renderers:FlyoutMenuBar id="flyoutMenuBar" creationComplete="flyoutMenuBar_creationCompleteHandler(event)" 
                labelField="@label" dataProvider="{mainMenuBarButtonData}" showRoot="false">
    </renderers:FlyoutMenuBar>

</s:WindowedApplication>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜