Hatena::ブログ(Diary)

jiroの日記 このページをアンテナに追加 RSSフィード

2007-10-29

[][]ActionScript 3.0 アニメーション

すごそう。

これは買ってみようと思う。とりあえず注文するかな。ていうか、明日発売か。。。直接本屋に行くか。。。


fladdict.net blog: 神の書 Make Things Move 日本語版発売

AS3のアニメーション本が出るらしいですよ - てっく煮ブログ

[]The Fisix Engine is an Actionscript 3.0 physics engine

miscellaneous ActionScript 3.0 Fisixサンプル

いつも面白い記事を読ませてもらってます。

で、今回は物理シミュレーションエンジンのサンプル。なんかに使えそうなんだけどなぁ

2007-10-24

[]クリックイベンドでListに入ったCheckBoxの値を変更する

ListをクリックしたタイミングでCheckBoxの値を変更するやり方。動作のイメージは上のような感じ。

まず、Listの各項目に対してCheckBoxを表示させるにはitemRendererを使います。itemRendererを使えば好きなレイアウトを行う事ができます。mx:Componentタグでレンダラを定義して、それをListのプロパティに設定します。これでひとまずCheckBoxをリストの中に表示する事ができます。

<mx:Panel width="100%" height="100%">
        <mx:List id="commentList" itemRenderer="{userRenderer}" height="100%" width="100%" click="select(event)" dataProvider="{users}"/>
        <mx:Button label="選択ユーザ確認" click="show();"/>
</mx:Panel>

<mx:Component id="userRenderer">
        <mx:HBox>
                <mx:CheckBox selected="{data.selected}"/>
                <mx:Label text="{data.name}"/>
        </mx:HBox>
</mx:Component>

次に、リストの項目をクリックしたときにクリックされた部分のチェックボックスに対応するデータプロバイダの値がとれれば良いのですが、直接取る事はできません。クリックしたItemの選択されたIndexを取得し、そのキーをもとにArrayCollectionからデータを取得します。また、dataProviderの値を変えただけでは反映されないので、itemUpdatedメソッドを使用して、値が更新された事を通知します。実はこのitemUpdatedがミソでこれをしらずにしばらくはまってしまいました。

private function select(event:MouseEvent):void {
    var selectedIndex:int = event.currentTarget.selectedIndex;
    var item:Object = users.getItemAt(selectedIndex);

    item.selected = !item.selected;
    users.setItemAt(item, selectedIndex);
    users.itemUpdated(item);
}

何故か、mx:Textを使ったときに文字列をクリックするとうまく選択できなかったんですが、なぜなんでしょう、、、ただのコーディングミスでした。

全てのソースは下に載せておきます。

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
        <mx:Script>
        <![CDATA[
                import mx.collections.ArrayCollection;
                import mx.controls.Alert;

                private function select(event:MouseEvent):void {
                        var selectedIndex:int = event.currentTarget.selectedIndex;
                        var item:Object = users.getItemAt(selectedIndex);

                        item.selected = !item.selected;
                        users.setItemAt(item, selectedIndex);
                        users.itemUpdated(item);
                }

                private function show():void {
                        var ar:Array = users.toArray();
                        var filterd:Array = ar.filter(function(e:*):* {
                                return !!e.selected;
                        });
                        Alert.show(filterd.map(function(e:*):*{ return e.name }).join());
                }
        ]]>
        </mx:Script>

    <mx:ArrayCollection id="users">
                <mx:Object name="田中" selected="true"/>
                <mx:Object name="山田"/>
                <mx:Object name="斉藤"/>
                <mx:Object name="本田" selected="true"/>
                <mx:Object name="宮本"/>
                <mx:Object name="西条"/>
                <mx:Object name="榎本"/>
        </mx:ArrayCollection>
        <mx:Panel width="100%" height="100%">
                <mx:List id="commentList" itemRenderer="{userRenderer}" height="100%" width="100%" click="select(event)" dataProvider="{users}"/>
                <mx:Button label="選択ユーザ確認" click="show();"/>
        </mx:Panel>

        <mx:Component id="userRenderer">
                <mx:HBox>
                        <mx:CheckBox selected="{data.selected}"/>
                        <mx:Label text="{data.name}"/>
                </mx:HBox>
        </mx:Component>
</mx:Application>

追記

ListにはitemClickイベントというものがあるんですね。これを使うのが正しそうです。

[][]TabNavigatorでListを表示する

私のような初心者が何も考えずに、TabNavigatorを使用してListを表示しようとするとこのようになります。

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="onload();">
        <mx:Script>
        <![CDATA[
                import mx.controls.Alert;
                private function onload():void {
                        one.dataProvider = silver;
                        two.dataProvider = gold;
                }
        ]]>
        </mx:Script>

        <mx:ArrayCollection id="silver">
                <mx:Object label="田中"/>
                <mx:Object label="山田"/>
                <mx:Object label="斉藤"/>
        </mx:ArrayCollection>
        <mx:ArrayCollection id="gold">
                <mx:Object label="本田"/>
                <mx:Object label="西条"/>
                <mx:Object label="榎本"/>
        </mx:ArrayCollection>

        <mx:TabNavigator width="100%" height="100%">
                <mx:VBox label="1つ目のタブ" width="100%" height="100%">
                        <mx:List id="one" width="100%" height="100%"/>
                </mx:VBox>
                <mx:VBox label="2つ目のタブ" width="100%" height="100%">
                        <mx:List id="two" width="100%" height="100%"/>
                </mx:VBox>
        </mx:TabNavigator>
</mx:Application>

二つ目のタブを表示してみてください。onloadメソッドで、two.dataProvider = gold;としているのにも関わらず、表示されません。TabNavigationのリファレンスを見ると次のように書いてあります。

コンテナに creationPolicy が指定されていない場合、そのコンテナは親の creationPolicy を継承します。アプリケーションに creationPolicy が指定されていない場合、デフォルトは ContainerCreationPolicy.AUTO になります。

creationPolicy が ContainerCreationPolicy.AUTO の場合、必要になるまでコンテナの一部またはすべての子孫の作成が遅延されます (遅延インスタンス化)。このポリシーを使用した場合、最初に作成される UIComponent が少なくなるため、起動時間が最短になります。ただし、ユーザーがアプリケーションの別の部分にはじめて移動するとき、ナビゲーションの遅延が生じます。 Accordion、TabNavigator、ViewStack などのナビゲータコンテナは、すべての子をただちに作成することによって ContainerCreationPolicy.AUTO ポリシーを実装しますが、ある子がそのナビゲータコンテナの選択された子になるまでは、その子のより深い子孫を作成しません。

とあります。つまり、creationPolicyプロパティを指定していないので、最初にdataProviderを指定したときにはまだtwoのコンポーネントは作成されていないんですね。ですので、dataProviderを最初に指定してもクリアされてしまうのでしょう。これを解消するためにcreationPolicyを設定しましょう。今回の使用方法だと、autoが良さそうです。ということで、このプロパティを指定すると問題なく表示されます。

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="onload();">
        <mx:Script>
        <![CDATA[
                import mx.controls.Alert;
                private function onload():void {
                        one.dataProvider = silver;
                        two.dataProvider = gold;
                }
        ]]>
        </mx:Script>

        <mx:ArrayCollection id="silver">
                <mx:Object label="田中"/>
                <mx:Object label="山田"/>
                <mx:Object label="斉藤"/>
        </mx:ArrayCollection>
        <mx:ArrayCollection id="gold">
                <mx:Object label="本田"/>
                <mx:Object label="西条"/>
                <mx:Object label="榎本"/>
        </mx:ArrayCollection>

        <mx:TabNavigator creationPolicy="all" width="100%" height="100%">
                <mx:VBox label="1つ目のタブ" width="100%" height="100%">
                        <mx:List id="one" width="100%" height="100%"/>
                </mx:VBox>
                <mx:VBox label="2つ目のタブ" width="100%" height="100%">
                        <mx:List id="two" width="100%" height="100%"/>
                </mx:VBox>
        </mx:TabNavigator>
</mx:Application>

2007-10-22

[]なんか見られてたらしい

id:noriyox密かに見られている事知った。トラックバックが無かったので知らなかったよ。

ちなみに最近取ったjiroxというドメインの最後のxはnoriyoxのパクリなのは秘密です。

[][]VimでActionScriptを色分けする

ActionScriptのsyntax定義が無いかなと思って、http://www.vim.org/をみてみたらありました。これを~/.vim/syntax/以下に配置します。あとは、~/.vim/ftdetect/actionscript.vimに以下のように書く

au BufNewFile,BufRead *.as      set filetype=actionscript

これで下のような感じに表示されます。

f:id:sukesam:20071022210637p:image

mxmlはここで説明されています。

[]Spriteをクリックしたときにフォーカスを与える

クリックしたときにフォーカスを当てるのに少し戸惑ったのでメモです。まず、動作しているものはこれ。

まず、矢印のSprite。focusRectをfalseに設定にしておくとフォーカスがあたったときにフォーカスの枠が表示されなくなります。プログラム中からSpriteに明示的にフォーカスを与えたい場合は、stageのfocusプロパティにフォーカスを与えるオブジェクトを指定します。

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        public class Study05Focus extends Sprite {
                public function Study05Focus():void {
                        for (var i:int = 0; i < 10; i++) {
                                var arrow:Study05Arrow = new Study05Arrow();
                                addChild(arrow);
                                arrow.x = Math.floor(320 * Math.random());
                                arrow.y = Math.floor(240 * Math.random());
                        }
                }
        }
}
package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.events.MouseEvent;
        import flash.events.FocusEvent;
        import flash.filters.DropShadowFilter;
        public class Study05Arrow extends Sprite {
                public function Study05Arrow():void {
                        draw(0x0000ff);

                        // フォーカスしたときに色を付けないようにする
                        focusRect = false;

                        addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
                        addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
                        addEventListener(FocusEvent.FOCUS_IN, focusIn);
                        addEventListener(FocusEvent.FOCUS_OUT, focusOut);
                }

                private function onMouseDown(event:MouseEvent):void {
                        stage.focus = this;
                        filters = [new DropShadowFilter()];
                        startDrag();
                }

                private function onMouseUp(event:MouseEvent):void {
                        stopDrag();
                        filters = [];
                }

                private function focusIn(event:FocusEvent):void {
                        draw(0xff0000);
                }

                private function focusOut(event:FocusEvent):void {
                        draw(0x0000ff);
                }

                private function draw(color:uint):void {
                        graphics.lineStyle(1, 0x000000);
                        graphics.beginFill(color);
                        graphics.moveTo(0, 15);
                        graphics.lineTo(0, 45);
                        graphics.lineTo(60, 45);
                        graphics.lineTo(60, 60);
                        graphics.lineTo(90, 30);
                        graphics.lineTo(60, 0);
                        graphics.lineTo(60, 15);
                        graphics.lineTo(0, 15);
                        graphics.endFill();
                }
        }
}

2007-10-21

[]packageの中にはクラス、変数、関数など何でも入る

そう、なんでも入るみたいです。逆にJavaのようにクラスのネストなんかはできません。

ただし、ファイル名と名前は一致している必要があります。

上のソース

Study04Namespace.mxml

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
        <mx:Script>
        <![CDATA[
                import mx.controls.Alert;
                import sample.Study04NamespaceClass;
                import sample.Study04NamespaceFunc;
                import sample.Study04NamespaceVar;
        ]]>
        </mx:Script>
        <mx:Label id="sampleLabel" text="initialized"/>
        <mx:Button label="class" click="sampleLabel.text = Study04NamespaceClass.showClass();"/>
        <mx:Button label="func" click="sampleLabel.text = Study04NamespaceFunc();"/>
        <mx:Button label="variable" click="sampleLabel.text = Study04NamespaceVar;"/>
</mx:Application>

パッケージにクラスを入れた例

sample/Study04NamespaceClass.as

package sample {
        public class Study04NamespaceClass {
                public static function showClass():String {
                        return "クラス";
                }
        }
}

パッケージに関数を入れた例

sample/Study04NamespaceFunc.as

package sample {
        public function Study04NamespaceFunc():String {
                return "関数";
        }
}

パッケージに変数を入れた例

sample/Study04NamespaceVar.as

package sample {
        public var Study04NamespaceVar:String = '変数';
}

これらをコンパイルするときには下のコマンドで行います

mxmlc Study04Namespace.mxml

ただし、sampleパッケージのファイルはsampleディレクトリに入っている必要があります。

2007-10-20

[]mxmlcでパッケージの中にあるソースだけをコンパイルする

例えば、こんなの

package sample {
        import flash.display.Sprite;
        import flash.text.TextField;;
        public class Study04Namespce2 extends Sprite {
                public function Study04Namespce2():void {
                        var text:TextField = new TextField();
                        text.text = "sample.Study04Namespce2";
                        text.width = 200;
                        addChild(text);
                }
        }
}

最初

$ mxmlc sample/Study04Namespce2.as

こんなふうにしてみたら

エラー: source-path で見つかったファイルのパッケージ構造 '' は、定義のパッケージ 'sample' と同じである必要があります。

とか言われてしまってたので、mxmlcのオプションをAbout the application compiler options -- Flex 2で確認してみたら、下のようにすれば良いっぽい

$ mxmlc -compiler.source-path+=. sample/Study04Namespce2.as
  • compiler.source-pathでソースのパスを指定しなきゃいけないっぽい。ここらへん、Javaと違ってちょっと面倒かな。

それと、mxmlcの使い方を調べてたら、id:nemu90kWwさんが説明してくれてた。mxmlcの使い方とコンパイルオプションを勝手に解説 - ◆nemu90kWw.の雑記。感謝

2007-10-19

[]JSONをActionScriptで扱う

ActionScriptでJSONを扱いたいので、調べてみるとas3corelibというライブラリがありました。これを使用すればJSON.decode(String)というように簡単にできます。

通信するアプリになるので、サンプルはここにおいておきます。ソースは以下の通り

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
        <mx:Script>
        <![CDATA[
                import mx.controls.Alert;
                import mx.collections.ArrayCollection;
                import mx.rpc.events.ResultEvent;
                import com.adobe.serialization.json.JSON;

                private function onJSONLoad(event:ResultEvent):void {
                        var text:String = new String(event.result);
                        var json:Array = JSON.decode(text);

                        var data:ArrayCollection = new ArrayCollection(json);
                        dg.dataProvider = data;
                }

                private function loadJSON():void {
                        jsonLoader.send();
                }
        ]]>
        </mx:Script>
        <mx:HTTPService id="jsonLoader" resultFormat="text" result="onJSONLoad(event)"
                url="./js/study_03.js"/>
        <mx:DataGrid id="dg" width="100%" height="100%" rowCount="5">
                <mx:columns>
                        <mx:DataGridColumn dataField="name" headerText="名前"/>
                        <mx:DataGridColumn dataField="age" headerText="年齢"/>
                </mx:columns>
        </mx:DataGrid>
        <mx:Button label="ロード" click="loadJSON();"/>
</mx:Application>

ちなみに、コンパイル時には下のように-include-librariesをつける必要がある。最初、-compiler.external-library-pathをつけてはまってしまった。ブラウザから起動するとなにも文句言ってくれないんだもの、、、

rascut -c "-include-libraries=corelib.swc" study_03_json.mxml 

2007-10-18

[]rascutすげー

ActionScriptを勉強していて、嫌だなぁと思っていたのが毎回のコンパイル。重いし、fcshを使ってもコマンド打つのめんどくさいなぁとか思ってたし。で、Comet使ってファイル監視して、自動コンパイル&リロードできるんじゃね?とか思ってたんですが、先人の方達はすでにそんな事はやられているようで、、、

ということでrascutすげー。そのまんまです。IDEなくても結構さくさくじゃんみたいな。説明はActionScript やるなら入れとけ。rascut 導入と使い方。 - てっく煮ブログでしてくれてます。作者のid:secondlifeさんに感謝です。

[]namespaceつきのノードからDataGridに値をバインドできない

上のようにうまくRSSから画像のURLをとって来れない。ネームスペース付きのノードをdataFieldにどうやって書くのかが分からない。もし分かる方がいたら教えてください。

それと、なんで取得したRSSと解釈したRSSが違うのかも分からない。本当なら、channelじゃなくてentryなんじゃないかと思うんだけど。。。分からない事がいっぱいです。

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Script>
	<![CDATA[
		import mx.controls.Alert;

		[Bindable]
		public var media:Namespace = new Namespace("http://search.yahoo.com/mrss/");

		private function loadRss():void {
			flickr.send();
			var media:Namespace = new Namespace("http://search.yahoo.com/mrss/");
		}
	]]>
	</mx:Script>
	<mx:HTTPService id="flickr" resultFormat="e4x"
		url="http://api.flickr.com/services/feeds/photos_public.gne?id=13347206@N07&amp;lang=en-us&amp;format=rss_200"/>
	<mx:DataGrid id="dg" width="100%" height="100%" rowCount="5" dataProvider="{flickr.lastResult.channel.item}">
		<mx:columns>
			<mx:DataGridColumn dataField="title" headerText="タイトル"/>
			<mx:DataGridColumn dataField="pubDate" headerText="日付"/>
			<mx:DataGridColumn dataField="data.media::content.@url" headerText="画像のURL"/>
		</mx:columns>
	</mx:DataGrid>
	<mx:Button label="ロード" click="loadRss();"/>
</mx:Application>

2007-10-17

[]ActionScriptを始めるにあたってまずドキュメント-

とりあえず、ここで必要なドキュメントはそろえられる。一番下に、ドキュメンテーションzipファイルがあるので、これを落とせばリファレンスもローカルで参照できます。

2007-10-16

[]flash始めました

id:nitoyonさんのはてなダイアリーに Flash を埋め込むガジェットを利用させてもらってます。実際仕事で使うようになるのだろうか。

[]Flex2のサンプルが素晴らしい

貧乏でIDEを買えないために、MXMLを自分で書かなければ行けないんですが、Flex SDKに付属するサンプルが素晴らしく、ほとんどコピペで何とかなります。これを触ってしまうと、なんで苦労してHTMLでレイアウトしていたんだろうと思ってしまう。

ActionScriptはJavaよりも柔軟だけれども、Javaと同じように大規模開発ができるように、工夫がこらしてあってとてもSIer向けの開発環境になっている。これからFlashに関して掘り下げていくけどもおそらく使わない理由はないと思う。

2007-10-03

[]Railsでロガーにタイムスタンプを追加する

RubyのデフォルトのLoggerはログのフォーマットに時間等が入っているのに、なぜRailsで使用するLoggerはタイムスタンプが出ていないんだろうと調べていて、id:elm200がまさにこの問題を解決してくれていました。id:elm200ありがとうございます。参考にさせていただきます。

Connection: close