Flexの最近のブログ記事

もしかしたら当たり前のことなのかもしれませんが、個人的には結構びっくりしたので覚書として記事に残しておきます。

下のサンプルは、ボタンをクリックすると 以下の処理を行います。
① Mathクラスのrandomメソッドを呼び 乱数を取得する
② 乱数値が奇数か偶数かを判別し、奇数ならば Boolean型の変数 oddNumを"true"に、偶数ならば"false"(デフォルト値) とします
③ oddNum 変数の評価を true/false の替わりに 1/0 で行います

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center">
<mx:Script>
    <![CDATA[
    
        private function getNum():void
        {
            var num:int;
            var oddNum:Boolean;
            
            num = Math.random() * 10;
                        
            if(num%2 > 0){
                oddNum = true;
            }
            
            if(oddNum == 0){
                numLabel.text = num + "は偶数です";
            }else if(oddNum == 1){
                numLabel.text = num + "は奇数です";
            }else{
                numLabel.text = "0 にも 1 にも入りませんでした";
            }
	} 
  ]]> 
</mx:Script> 
<mx:Label id="numLabel" text="下のボタンをクリックして数値を取得してください" fontSize="15" 
 color="#FFFFFF" fontWeight="bold"/> 
<mx:Button label="クリックして数値を表示" click="getNum()" width="200" height="30"/> 
</mx:Application>

boolean の評価を true/false ではなく 1/0 でできることにより得られるメリットはこれと言って浮かばないのですが・・
ビルド時にも実行時にも怒られず、型変換の意識もせずにすんなりと動いてしまうのはちょっと恐いかなと。
意図的にはやらないとは思いますが、こんなこともできてしまうのだと気をつけたいと思います。

 今回は、Adobe Illustrator CS5で作成したデザインを、Flash Catalyst CS5を使用してFlashBuilder4にインポートする方法を紹介致します。

初めに、Adobe Illustrator CS5でアプリケーションのデザインを作成します。サンプルでは以下の様なデザインを作成しました。

blog0810-2.png

デザインが完成したら、ファイル(F)>保存(S)から.aiの形式で保存します。

次に、Flash Catalyst CS5を起動し、TOP画面のウィザードの「デザインファイルから新規プロジェクトを作成」からAdobe Illustratorファイル(AI)から・・・を選択し、先ほどAdobe Illustratorで作成した.aiファイルを選択します。

blog0810-4.png

Flash Catalystでは、Adobe Illustrator(CS4以降)で作成したデザインを、簡単にコンポーネントに変換する事が可能です。
先ほど作成したデザイン内の矢印のグループを選択し、ボタンに変換を行います。

blog0810-7.png

ボタンへの変換後、ボタンのステート(up,over,down,disabled)毎にデザインを設定する事が可能です。
ここでは、マウスオーバー時とマウスダウン時にボタンの周りが光るようなフィルタを適用しました。

blog0810-8.png

右上のパネルの「ワイヤーフレームコンポーネント」タブからコンポーネントを追加する事も可能です。

blog0810-9.png

Flash Catalystでの編集中に、元のデザインに修正を加える事も可能です。
右上のパネルの「レイヤー」タブで右クリックし、「Adobe Illustrator CS5で編集(L)」を選択します。

blog0810-10.png

以下のポップアップが表示され、Adobe Illustrator CS5が起動します。

blog0810-11.png

デザインを修正し、完了したら「○完了」ボタンをクリックします。今回は新たにグループを追加しました。

blog0810-12.png

完了ボタンクリック後、デザインは保存され、修正内容は自動的にFlash Catalyst側にも反映されます。既にFlash Catalyst側で設定した内容はそのままなので安心です(再度設定し直す必要はありません)

Flash Catalystではステート変更時のアニメーション(トランジション)を簡単に設定する事が可能です。 先ほど追加したグループをボタンに変換し、「Up→Down」時に3D回転するエフェクトを設定してみました。 エフェクトの追加は「アクションの追加」ボタンから選択を行います。

blog0810-14.png

編集が完了したら、ファイル(F)>保存(S)でFXP形式で保存を行います。

blog0810-15.png

次に、FlashBuilder4を起動します。パッケージエクスプローラーで右クリックし、インポート(I)を選択します。

blog0810-16.png

FlashBuilder>FlashBuilderプロジェクトを選択し、次へ(N)ボタンをクリックします。

blog0810-17.png

プロジェクトを読み込み>ファイル(F)で、Flash Catalystで作成したFXPファイルを選択し、終了(E)ボタンをクリックします。

blog0810-18.png

FXPからFlashBuilderプロジェクトが生成されます。 default packageのMain.mxmlを開くとFlash Catalystで編集したデザイン通りインポートされた事が確認できます。 更に、componentsパッケージではFlash Catalystで変換を行ったコンポーネントのmxmlが生成されている事が確認できます。

blog0810-19.png

ボタンにコンポーネント変換したものは、sparkコンポーネントのボタンに変換がおこなわれます。

blog0810-20.png

componentsパッケージ配下のmxmlで各部品の修正・編集を行う事も可能です。

blog0810-21.png

最後に、プログラムロジックを実装して完成です。 Flash Catalystでボタンに変換した矢印ボタンですが、ボタン内の画像部分のみコンポーネントとして認識されます。(ちゃんと空白部分をくり抜いたコンポーネントとなります) このようにFlash Catalystとの連携を行う事により、より高度なデザインのアプリケーションを作成する事が可能です。

blog0810-22.png

 

<完成したサンプルアプリ>

SAMPLE

※サンプルは別ウインドウで開きます
※サンプルの再生はFlashPlayer10.1が必要となります。

なんとなくですが、AMFのパケットの中身はどうなっているのだろうか?と思い立って調べてみました。

Googleで、「AMF パケット 仕様」で調べた結果、AdobeがAMF規格の仕様をPDFファイルで公開していたのを見つけました。

AMF0  http://opensource.adobe.com/wiki/download/attachments/1114283/JP_amf0_spec_121207.pdf
AMF3  http://opensource.adobe.com/wiki/download/attachments/1114283/JP_amf3_spec_121207.pdf

上のPDFですと私自身はいまひとつ分かりにくかったので、以下表にして簡単にまとめてみました。

AMFパケットの仕様

項目 説明
AMFパケットのバージョン  U16 AMFパケットのバージョン
AMF3=3
AMF0=0
ヘッダー数  U16 ヘッダーの数

 ヘッダー

※ヘッダー数分繰り返す

 ヘッダー名称サイズ  U16  ヘッダー名称の文字列長
 ヘッダー名称  UTF8 ヘッダー名称
文字列の長さはヘッダー名称サイズ
 ヘッダーのバイト長  U32 ヘッダーのバイト長
※わからない場合は(U32)-1
 value-type    
 AMFメッセージ数  U16  AMFメッセージ(ボディ)の数

 AMFメッセージ部

※AMFメッセージ数分繰り返す

 ターゲットURIサイズ  U16  ターゲットURIの文字列長
 ターゲットURIサイズ  UTF8  ターゲットURI名称
文字列の長さはターゲットURIサイズ
 レスポンスURIサイズ  U16  レスポンスURIの文字列長
 レスポンスURIサイズ  UTF8  レスポンスURI名称
文字列の長さはレスポンスURIサイズ
 メッセージのバイト長  U32  メッセージのバイト長
※わからない場合は(U32)-1
 value-type    

U8 = 符号なしのバイト、8 ビットのデータ、オクテット
U16 = ビッグエンディアン(network)バイトオーダで記された符号なしの16 ビット整数
U32 = ビッグエンディアン(network)バイトオーダで記された符号なしの32 ビット整数

 ドキュメントを読んでも、value-type の部分がいまいち謎です。

こういうことに今まで興味がわかなかったのは技術者としては?でしょうが、今回調べたことでAMFの中身についてある程度知ることができました。
そのうち、パケット解析ツールなどを使用して実際のデータを除いてみたいと思います。

JavaScriptと連携する際、ExternalInterfaceを使用しますがエラーハンドリングに関して注意が必要です。
以下はExternalInterfaceを使用した一般的なサンプルです。 エラーハンドリングの為にtry~catch~ステートメントを使用しております。

<mxmlコード>



	
		
	

	
		
	
	




<javaScript(index.template.htmlに実装)>

        function testFunc()
        {
        	window.alert("TestJs");
        	${application}.callBack();
        
        }

JavaScriptの呼び出しを行うイベントハンドラにおいて、「ExternalInterface.marshallExceptions = true;」という処理を実装しておりますが、実はmarshallExceptionsをtrueに設定しておかないと、コールバック先のイベントでthrowしたErrorが無視されてしまう為注意が必要となります。
marshallExceptionsの詳細は以下の通り。

ji100606-1.png

ただし、marshallExceptionsはFlexBUilder3から使用可能な機能なので、コンパイラのバージョンが3以前の場合は使用できません。
私の職場のシステムはFlex2立った為、marshallExceptionsを使用できず困った問題となってしまいました。エラー用のEventを作成しエラー時にdispatchする方法で回避致しましたが他に回避策は無いようです。

ExternalInterface使用時は注意が必要です。

Flex の DataGrid で、列の定義をするのに DataGridColumn を使いますが、それを、2つの DataGrid で同じ DataGridColumn を共有し、それぞれの DataGrid の列定義を同期させてみようという小ネタをご紹介します。
例として、上下に並べた DataGrid で、どちらかの列幅を変えたときにもう片方の列幅も一緒に変更されるといったことをやってみました。

以下がサンプルソースになります。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"
	creationComplete="creationCompleteHandler(event)">
	<mx:Script>
		<![CDATA[
			import mx.events.DataGridEvent;
			import mx.events.FlexEvent;
			
			private var dgColumns:Array = new Array();
			
			[Bindable]
			private var dgData1:Array = [
			{no:1, name:'氏名1-1', age:21, address:'住所1-1'},
			{no:2, name:'氏名1-2', age:22, address:'住所1-2'},
			{no:3, name:'氏名1-3', age:23, address:'住所1-3'},
			{no:4, name:'氏名1-4', age:24, address:'住所1-4'},
			{no:5, name:'氏名1-5', age:25, address:'住所1-5'}
			];
			[Bindable]
			private var dgData2:Array = [
			{no:1, name:'氏名2-1', age:31, address:'住所2-1'},
			{no:2, name:'氏名2-2', age:32, address:'住所2-2'},
			{no:3, name:'氏名2-3', age:33, address:'住所2-3'},
			{no:4, name:'氏名2-4', age:34, address:'住所2-4'},
			{no:5, name:'氏名2-5', age:35, address:'住所2-5'}
			];
			
			public function creationCompleteHandler(event:FlexEvent):void
			{
				dataGrid2.columns = dataGrid1.columns;
				
				dataGrid1.addEventListener(DataGridEvent.COLUMN_STRETCH, dgColumnStretch);
				dataGrid2.addEventListener(DataGridEvent.COLUMN_STRETCH, dgColumnStretch);
			}
			
			public function dgColumnStretch(event:DataGridEvent):void
			{
				if (event.currentTarget == dataGrid1)
					dataGrid2.invalidateList();
				else
					dataGrid1.invalidateList();
			}
		]]>
	</mx:Script>
	
	<mx:VBox>

	<mx:DataGrid id="dataGrid1" dataProvider="{dgData1}">
		<mx:columns>
			<mx:DataGridColumn headerText="NO" dataField="no"/>
			<mx:DataGridColumn headerText="氏名" dataField="name"/>
			<mx:DataGridColumn headerText="年齢" dataField="age"/>
			<mx:DataGridColumn headerText="住所" dataField="address"/>
		</mx:columns>
	</mx:DataGrid>
	
	<mx:DataGrid id="dataGrid2" dataProvider="{dgData2}">
	</mx:DataGrid>

	</mx:VBox>
</mx:Application>


上記ソースでは、2つ目の DataGrid の columns プロパティを定義せずに、アプリケーションの creationCompleteイベントのハンドラーで、dataGrid1 の columns プロパティをそのままコピーしています。

	dataGrid2.columns = dataGrid1.columns;

この時点で、上下の DataGrid の列定義が同じになり、上の DataGrid と 下の DataGrid の列定義(ヘッダー文字列、表示する内容など)が同じものになります。
このままですと、同じ DataGridColumn を使っているだけですので、初期表示の列定義をコピーしただけになります。

そこで、それぞれの DataGrid の columnStretch イベントのハンドラーメソッドで、お互いの invalidateList メソッドを呼んで描画をリフレッシュするようにします。

	private function dgColumnStretch(event:DataGridEvent):void
	{
		if (event.currentTarget == dataGrid1)
			dataGrid2.invalidateList();
		else
			dataGrid1.invalidateList();
	}

すると、上下の DataGrid の列幅が、常に同期するということができるようになります。
同じ DataGridColumn を見に行っているので当たり前といえば当たり前です。
ただ、列幅変更時にリフレッシュしない場合、表面上はそれぞれの DataGrid の列幅が違いますが、裏側では同じですので、再表示のタイミングでいきなり列幅が変わるという見方によっては不具合と捉えられる怪しい挙動をしてしまいます。

以下が、上記ソースで作成したFlexアプリケーションのサンプルになります。
上下それぞれの DataGrid の列幅を変更して、実際の動作を試してみてください。

最後に、DataGrid の columns プロパティは Arrayクラスですが、値を取得または設定するとき、元データの一連のエレメントを取り出して、新しい配列で取得または設定する sliceメソッドを使用しています。

そのため、列の順序を変更した場合は、上記のやり方だけですと上下の DataGrid で別々の列順序になってしまいます。

列の順序を変更した場合は、DataGrid の headerShift イベントのハンドラーメソッドなどで、columns の順序も考慮した同期を取るようにしたほうが良いと思います。

<<前のページ 12345

このブログについて

このブログは吉祥寺にあるブレインチャイルド株式会社の社員で投稿しています。
業務ではまってしまったことや発見したこと。
自分達で新たに学習してみようと思って勉強し始めたことなどを綴っています。
こんな社員が働いているブレインチャイルドに興味がわいててきたなら、是非お問い合わせください。
会社案内
求人案内
先輩のコメント