こんにちは!

今回はFlexで、プルダウンを実現するComboBoxコンポーネントとメニューを実現するMenuを使って、多段化したプルダウンメニューを作ってみました。
「プルダウンをクリック→カテゴリや区分を選んでマウスオーバー→さらに出てきた項目をクリックして選択」
というような動作を目指しました。

実行結果は以下のようになります。

multiPullDown.swf

ソースはコチラ.zip。↓にも表示しています。

ポイントは、ComboBoxのcloseメソッドをオーバーライドして閉じるタイミングを管理すること、サブメニューの方をクリックした時にComboBoxのpromptを設定することです。

○メインのアプリケーションmxml

<?xml version = "1.0" encoding = "utf-8"?>
<mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml"
	layout = "absolute"
	applicationComplete = "init();"
	xmlns:local = "*">

	<mx:Script>
		<![CDATA[
			import mx.events.ListEvent;
			import mx.events.MenuEvent;
			import mx.controls.Menu;
			import mx.collections.ArrayCollection;
			
			[Bindable]
			private var _arrayCorrection:ArrayCollection =
				new ArrayCollection
				([
					{label:"性別", subData:[
						{label:"男", group:"性別", data:1},
						{label:"女", group:"性別", data:2}
					]},
					{label:"血液型", subData:[
						{label:"A型", group:"血液型", data:1},
						{label:"B型", group:"血液型", data:2},
						{label:"O型", group:"血液型", data:3},
						{label:"AB型", group:"血液型", data:4}
					]}
				]);
			private var _subMenu:Menu;
			private var _selectedSubMenuItem:Object;

			//customComboBox内のアイテムをクリックした時の処理
			private function onValueCommit():void
			{
				//クリックした際に項目名が反映されると不自然なので、常にselectedIndexを-1にします。
				if(this.customComboBox.selectedIndex != -1)
				{
					this.customComboBox.selectedIndex = -1;
				}
				
				//また、開いていたサブメニューが「画面外のクリック」と判定して閉じてしまうため、開き直します。
				if(this._subMenu != null)
				{
					this._subMenu.show();
				}
			}
			
			//customComboBox内のアイテムにロールオーバーした時の処理
			private function onItemRollOver(evt:ListEvent):void
			{
				//既にサブメニューを生成していた場合は一旦nullにして消します。
				if(this._subMenu != null)
				{
					this.removeChild(this._subMenu);
					this._subMenu = null;
				}
				
				//ロールオーバーしたアイテムのグローバル座標を計算します。スキン等の設定によっては微調整が必要かと思います。
				var p:Point = new Point(evt.itemRenderer.x + evt.target.width - 5, evt.itemRenderer.y + evt.target.height - 3);
				p = this.customComboBox.localToGlobal(p);
								
				//ロールオーバーしたアイテムの"subData"配列からサブメニューを生成します。
				this._subMenu = Menu.createMenu(this, this._arrayCorrection[evt.rowIndex].subData as Array, false);
				this.addChild(_subMenu);
				
				//ロールオーバーしたアイテムの座標にサブメニューの座標を移動。
				this._subMenu.x = p.x;
				this._subMenu.y = p.y;
				
				//サブメニューを開きます。
				this._subMenu.show();
				this._subMenu.addEventListener(MenuEvent.ITEM_CLICK, onSubMenuClick);
			}
			
			//サブメニュー内のアイテムをクリックした時の処理
			private function onSubMenuClick(evt:MenuEvent):void
			{
				//customComboBoxに表示されるテキストをサブメニューで選択されたものにします。
				this.customComboBox.prompt = evt.item.label;
				//サブメニュー内でクリックしたデータを保持しておきます。
				this._selectedSubMenuItem = evt.item;
				this.output.text = "選択されたアイテムは -> " + this._selectedSubMenuItem.group + ", " + this._selectedSubMenuItem.label;
				
				//サブメニューは閉じるので、ついでに廃棄してしまいます。
				this.removeChild(this._subMenu);
				this._subMenu = null;
			}
		]]>
	</mx:Script>

	<mx:VBox x="10" y="10">
		<mx:Label id="output" text="↓選択してください。" />
		<local:CustomComboBox id = "customComboBox"
			prompt = "選択してください"
			dataProvider = "{_arrayCorrection}"
			itemRollOver = "onItemRollOver(event);"
			valueCommit="onValueCommit();"/>
	</mx:VBox>

</mx:Application>

○CustomComboBox.mxml

<?xml version = "1.0" encoding = "utf-8"?>
<mx:ComboBox xmlns:mx = "http://www.adobe.com/2006/mxml">

	<mx:Script>
		<![CDATA[
			public override function close(trigger:Event=null):void
			{
				//Menuコンポーネントをshow()した際に閉じないよう、このメソッドをオーバーライドして
				//閉じたい時だけ閉じるようにします。
				if(trigger)
				{
					//trace(trigger.type);
					switch(trigger.type)
					{
						case "mouseDownOutside":
							//プルダウン以外の場所でマウスクリックされた時はこのタイプが渡されてきます。この場合は閉じます。
							super.close(trigger);
						break;
						default:
							//上記以外のタイプの場合は閉じない。
						break;
					}
				}
			}
		]]>
	</mx:Script>

</mx:ComboBox>

 

HTML5飯