Avg. Rating 5.0

Problem

When using a ComboBox, the menu for the ComboBox is clipped by the stage. If you need wide menu items, you have little choice by place the ComboBox so that this isn't an issue.

Solution

This example extends a ComboBox to use the NativeMenu class (flash.display.NativeMenu) to display the menu for the ComboBox, eliminating this problem.

Detailed explanation

The thing to look at is the NativeComboBox class: 

    public class NativeComboBox extends ComboBox

We're extending ComboBox because want all of the standard ComboBox look and feel. All
we want to do is change the actual menu mechanism.

We declare a private NativeMenu (flash.display.NativeMenu - an AIR api), and then
instantiate it in the class' constructor.

        private var nm: NativeMenu;
        public function NativeComboBox()
        {
            nm = new NativeMenu();
            nm.addEventListener(Event.SELECT, handleSelect );
            addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown, true);
        }

Note the event listeners I've added. The first one is added to eh NativeMenu and handles the select event. The second intercepts the Mouse Down event for the ComboBox. That event allows us to flip up the NativeMenu and prevent the normal ComboBox menu from displaying.

The onMouseDown hander simply takes the event, resets the NativeMenu and creates the menu items based on the data provider for the ComboBox (our base class). The last line in the method stops the Mouse Down event's propagation, which prevents the normal ComboBox menu from showing.      

        private function onMouseDown( event: MouseEvent ): void
        {
            nm.removeAllItems();
            var ac: ArrayCollection;
            if ( this.dataProvider is Array )
            {
                ac = new ArrayCollection( this.dataProvider as Array );
            } else
            {
                ac = this.dataProvider as ArrayCollection;
            }
            for ( var i: int = 0; i < ac.length; i++ )
            {
                var nmi: NativeMenuItem = new NativeMenuItem( ac.getItemAt( i ).toString() );
                nm.addItem( nmi );
            }
            nm.display( this.parentApplication.stage, event.stageX, event.stageY );
            event.stopPropagation();
        }

Finally, we have to handle the selection. All we have to do is find the index of the item the user selected, and set the ComboBox ("this" because we're based on ComboBox) selectedIndex property. From there we simply create the ListEvent.Change event and dispatch it.

        private function handleSelect( event: Event ): void
        {
            var nmi: NativeMenuItem = event.target as NativeMenuItem;
            var idx: int = nm.getItemIndex( nmi );
            this.selectedIndex = idx;
            var evt: ListEvent = new ListEvent( ListEvent.CHANGE, false, true, 0, idx );
            this.dispatchEvent( evt );
        }

Using this new class is about as easy as it gets. Because it's based on a ComboBox, it acts just like one in the mxml file. We do have to add a namespace declaration to use it, though:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" historyManagementEnabled="false" width="300" height="300"
                xmlns:menu="menu.*" creationComplete="creationComplete()">
    <mx:Script>
        <![CDATA[
            import flash.display.NativeMenu;
            import flash.display.NativeMenuItem;
           
            import mx.controls.Alert;
            import mx.events.ListEvent;
           
            private function creationComplete(): void
            {
                combo.addEventListener( ListEvent.CHANGE, selectionChangedHandler );
            }
            private function selectionChangedHandler( evt: ListEvent ): void
            {
                var idx: int = evt.rowIndex;
               
                trace( "Selected Thingy: " + combo.selectedLabel);
            }
           
        ]]>
    </mx:Script>
        <menu:NativeComboBox id="combo" x="203" y="10" width="87" dataProvider="[Fred,Wilma,Barney,Betty]" enabled="true"></menu:NativeComboBox>
       
</mx:Application>


+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes