Flex菜单快捷键和自定义渲染器

时间:2011-06-24 05:26:43

标签: flex flex4

我需要创建一个菜单组件,其中每个菜单项如下所示:

图标标签右对齐键盘快捷键

我尝试创建自定义菜单项渲染器,但a)键盘快捷键没有右对齐 b)子菜单存在很多问题。

我还尝试使用数据网格和面板及其混合来绘制这种菜单,但它太乱了。

关于如何实现这一目标的任何指示?

编辑:添加源代码

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;
        import 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

包 {     [绑定]     公共类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

包 {     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();
    }
}

}

来自justfortechies.com的CustomMenuItemRenderer.as / * * /

包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);
    }
}

}

来自justfortechies.com的ValueObject.as / * * /

包com.jusfortechies.controls {     [绑定]     公共类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;
    }

}

}

1 个答案:

答案 0 :(得分:2)

这是我打算做同样事情的MenuBar实验的源代码 - 使用自定义渲染器显示不同类型的菜单。

P.S。:这不是这个问题的答案。创建这篇文章是为了区分我采取的两种方法。

<强> 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>