アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

【Flex3】「Flex3の、こんなときどうするの??」

こんにちは、最近モールス信号に興味深々の橋本です。

さて、今回は前回の「AS3のこんなときどうするの?」の続編で、

Flex3のこんなときどうする?」をテーマに、また思いついたところを適当に書いていきたいと思います。

アサインされてるプロジェクトを進める中で発見したものばかりなので、結構偏りがあるかもしれませんが、そこはご了承くださいませ。。。

では、どぞー。

1. スクリプトの中で値をバインドしたい

Q. mxmlの中で値をバインドするときには、バインドしたい変数をmxmlの中で{}で囲み、対象の変数に、[Bindable]タグをつければオッケーなんだけど、スクリプトの中で、値をバインドさせたいときはどうするの??

A. BindingUtilsクラスを使いましょう。
BindingUtils.bindProperty()を使うことで、プロパティ同士をバインドさせることができます。



var textInput:TextInput = new TextInput();
addChild(textInput);
				
var label:Label = new Label();
addChild(label);

BindingUtils.bindProperty(label, "text", textInput, "text");


bindSetterメソッドを使うことで、対象の変数が変化したときに、特定のメソッドを呼び出すこともできますよ。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				creationComplete="application1_creationCompleteHandler(event)"
				>
	<mx:TextInput id="textInput"/>
	<mx:Label id="hoge"/>
	<mx:Script>
		<![CDATA[
			import mx.binding.utils.BindingUtils;
			import mx.controls.Label;
			import mx.controls.TextInput;
			import mx.events.FlexEvent;
			

			protected function application1_creationCompleteHandler(event:FlexEvent):void
			{
				BindingUtils.bindSetter(toUpperCase, this.textInput, "text");
			}
			
			private function toUpperCase(str:String):void
			{
				this.hoge.text = str.toUpperCase();
			}
		]]>
	</mx:Script>
</mx:Application>


2. 自分で作ったクラスのプロパティをバインドの対象にしたい

Q. 自分で作成したクラス内のプロパティをバインドの対象にしたい。でも、呼び出し元で[Bindable]タグをつけるわけにもいかないし、BindingUtils使おうと思っても、対象外って怒られるし、どうするの??

A. 自分で作成したクラス内の変数のセッター内で、イベントをdispatch。Bindableタグの中で、そのイベントを指定するとバインドの対象にできますよ。
こんな感じです。



var hoge:String;

//セッターの中で、設定したイベントをdispatch。Bindableタグで、イベントを指定
[Bindable(event="hogeChange")] 
public function set hoge(value:String):void
{
	dispatchEvent(new Event("hogeChange"));
	hoge = value; 
}


3. 独自イベントをmxmlの選択項目にいれたい

Q. 自分でカスタムしたコンポーネントを呼び出すときに、独自イベントをmxmlで指定したいんだけど、どうするの??

A. コンポーネント内のMetadataタグの中にイベント名を記載しておきましょう。そうすることで、後からmxml上で使うことができます。



<mx:Metadata>
	[Event(name="hoge",type="flash.events.Event")]
</mx:Metadata>


4. DataGridの背景色を変更したい

Q. DataGridの背景色をセル毎に変えたいんだけど、どうするの??

A. DataGridColumnのitemRendererのbackgroundプロパティをtrueにして、backgroundColorを設定することで変更できますよー。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				xmlns:components="components.*"
				creationComplete="application1_creationCompleteHandler(event)"
				>
	<mx:DataGrid dataProvider="{dataList}"
				 width="100%"
				 height="100%"
				 >
		<mx:columns>
			<mx:DataGridColumn headerText="hoge" dataField="data" itemRenderer="components.Hoge"/>
		</mx:columns>
	</mx:DataGrid>
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;

			[Bindable]
			private var dataList:ArrayCollection;
			
			protected function application1_creationCompleteHandler(event:FlexEvent):void
			{
				var arr:ArrayCollection = new ArrayCollection();
				for (var i:int = 0; i < 100; i++)
				{
					var obj:Object =
						{
							data: i
						}
					;
					
					arr.addItem(obj);
				}
				
				dataList = arr;
			}

		]]>
	</mx:Script>
</mx:Application>


itemRenderer用のクラス


package components
{
	import mx.controls.dataGridClasses.DataGridItemRenderer;
	
	public class Hoge extends DataGridItemRenderer
	{
		
		public function Hoge()
		{
			super();
			
			this.background = true;
			// ランダムの色を入れる
			this.backgroundColor = Math.random() * 0xFFFFFF;
		}
	}
}


5. DataGridに文字列以外のものを表示したい

Q. DataGridに、ボタンとか画像とかチェックボックスとか、その他諸々を表示したいんだけど、どうするの??

A. DataGridColumnのitemRendererに、表示したいコンポーネントのクラスを指定することで変更することができますよー。
mxmlで指定するときには、一つ前のサンプルの中でやっているような感じで、クラス名を指定してやればオッケーです。
スクリプトで指定するときには、ClassFactoryクラスのインスタンスを指定してやればオッケーです。



var column:DataGridColumn = new DataGridColumn();
column.itemRenderer = new ClassFactory(Hoge);


6. ツリーに文字列以外のものを表示したい

Q. ツリーにボタンとか画像とかチェックボックスとか、その他諸々を表示したいんだけど、どうするの??

A. DataGridのときと同様に、itemRendererを指定することで可能です。
ただ、チェックボックスを表示するときは要注意。DataGridやTreeなどの、ListベースのコンポーネントのitemRendererは内部で使いまわされるので、チェックした状態を保持しておく機構が必要です。

以下の例では、TreeのdataProviderに指定しているXMLに、selectedというAttributeを持たせて、それを変更することによって、チェック状態を保持しています。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				xmlns:components="components.*"
				>
	<mx:Tree itemRenderer="components.Hoge" dataProvider="{xml}" width="100" labelField="@value"/>
	<mx:Script>
		<![CDATA[
			[Bindable]
			private var xml:XMLList = XML(
				<root>
					<node selected="false" value="1"/>
					<node selected="false" value="2"/>
					<node selected="false" value="3"/>
					<node selected="false" value="4"/>
					<node selected="false" value="5"/>
					<node selected="false" value="6"/>
					<node selected="false" value="7"/>
					<node selected="false" value="8"/>
					<node selected="false" value="9"/>
					<node selected="false" value="10"/>
				</root>
			).node;
		]]>
	</mx:Script>
</mx:Application>


チェックボックスを表示するためのカスタムitemRendererクラス


package components
{
	import mx.binding.utils.BindingUtils;
	import mx.controls.CheckBox;
	import mx.controls.treeClasses.TreeItemRenderer;
	import mx.controls.treeClasses.TreeListData;
	
	public class Hoge extends TreeItemRenderer
	{
		[Bindable]
		public var checkBox:CheckBox;
		
		public function Hoge()
		{
			super();
		}
		
		override public function set data(value:Object):void {
			super.data = value;
		}
		
		override protected function createChildren():void{
			super.createChildren();
			
			checkBox = new CheckBox();
			checkBox.setStyle("verticalAlign","middle");
			BindingUtils.bindSetter(setSelected, checkBox, 'selected');
			this.addChild(checkBox);
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {     
			var treeListData:TreeListData = TreeListData(super.listData);
			
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			
			if(super.data)
			{
				if (data.@selected.toString() == 'true')
				{
					checkBox.selected = true;
				}
				else
				{
					checkBox.selected = false;
				}
				
				checkBox.x = super.label.x;
				checkBox.y = ( unscaledHeight - checkBox.height ) /2;
				label.x = checkBox.x + checkBox.width + 20;
			}
		}
		
		private function setSelected(selected:Boolean):void
		{
			if (data)
			{
				data.@selected = selected.toString();
			}
		}
	}
}


7. drag and drop時の画像を変更したい

Q. drag and dropを独自に実装したときに、ドラッグする対象の画像を変更したいんだけど、どうするの??

A. DragManagerクラスのdoDragメソッドの第四引数に画像を指定してやればオッケーです。



DragManager.doDrag(dragInitiator, dragSource, event, img);


8. カーソルを変更したい

Q. 処理待ち中のカーソルを変更したりしたいんだけど、どうするの??

A. cursorManager変数の各種メソッドを使えば可能ですよー。

cursorManager.setBusyCursor()で、デフォルトの時計のアイコンを表示することができます。
cursorManager.removeBusyCursor()で、普通のアイコンに戻せます。

CursorManager.setCursor()を使うことで、独自のアイコンを指定することもできますよー。

9. ラッパーのhtmlのtitleをswfの中で設定したい

Q. htmlのタイトルを変更したいんだけど、どうするの??

A. ExternalInterfaceクラスを使いましょう。そうすることで、swfから、javascriptを実行することができます。



ExternalInterface.call("function(){if(location.href.indexOf('#',0) != -1){document.title = 'hogehoge'}}");


ラッパーhtmlの中でタイトルを最初から指定しておけばいいんじゃネーノ?って思うかもしれませんが、IEだけちゃんと動かないんですよ。なぜか'#'って表示されちゃうんですよね。

10. swfの置いてあるURLを取得したい

Q. swfの実行元のURLを取得して、swfの内部で使いたいんだけど、どうするの??

A. Application.application.urlで、実行されているswfのURLをフルで取得できるので、そこから正規表現で取得しましょう。



private function getHost():String
{
	var fullUrl:String = Application.application.url;
	var reg:RegExp = new RegExp("http://[^/]*/");
	if (reg.test(fullUrl)) {
		return reg.exec(fullUrl).toString();
	}
}


以上でーす。

結構偏った内容なんですが、お役にたてることが一つでもあれば幸いです。
ではではー。