VM on Flash

Flash上で動くプログラミング言語のVMを色々探してみたので、ここに書いておきますね。

Lua-Alchemy (Lua on Flash)
http://code.google.com/p/lua-alchemy/
[Flash] Flash 上で Lua を動かす
http://hikipuro.blog105.fc2.com/blog-entry-428.html

HotRuby (Ruby on Flash)
http://hotruby.yukoba.jp/index.html

D.eval (ActionScript3 on Flash)
http://www.riaone.com/products/deval/index.html

こんなとこかな。
もし、他に何か知っている人いたら教えてくだしあ。

独自メタデータタグを作る方法

Firefoxに初めて、並々ならぬ殺意を覚えた。

なに、俺が珍しくブログ書いてる時に何の前触れも無く落ちやがる。

もう、全部消えたやないけ!

泣くぞ?俺は泣くと手が付けられないんだからな!?

(ノ_<、)

恨み言はこれくらいにして、書き直します。

いいんだ、どうせ僕のポストなんて大宇宙の意思に比べたら全然小さいんだ。だから別に消えても世界は同じように回るんだ。

独自メタデータタグを作る方法

前回のポストでメタデータタグがあまりに便利だったので、オレオレメタデータタグが作りたくなった。以上。

投げやり?苦情はFirefoxに言ってくれ。

そんなこんなで、独自のメタデータタグを作る方法を調べてみました。

Annotating ActionScript Classes with Custom Metadata + Simple ORM Framework for AIR
http://coenraets.org/blog/2007/10/annotating-actionscript-classes-with-custom-metadata-simple-orm-framework-for-air/

AS3で独自メタデータの保持
http://www.be-interactive.org/?itemid=202

上のサイトは英語です。でも、独自メタデータをどうやって使うかがサンプルコードを見ると分かります。
describeTypeっていう関数を使って、インスタンスからクラス構造をXMLで取得できるので、そのXMLを解析すればメタデータタグの情報が取得できるってわけです。

下のサイトはBeInteractive!のyossyさんが独自メタデータタグを使ったコードのビルド方法について書かれている記事です。
これを参考にビルドしてみました。

サンプル

Player.as

package me.rkome.da.labs
{
    public class Player
    {
        public function Player()
        {
        }

        private var _test:String;

        [DarkOmeme("programmer")]
        public function set test(val:String):void
        {
            _test = val;
        }
        public function get test():String
        {
            return _test;
        }
    }
}

サンプルとしてこんなクラスを作ってみました。クラス名は適当です。本当は理由があったんだけど、迷宮入りです。Firefoxに言ってください。

testってプロパティにDarkOmemeって独自メタデータを付加して、値として"programmer"という文字列を渡しています。

さて、ではこいつのインスタンスを実際にdescribeTypeして見ましょう。

MetadataApp.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCreationComplete()">
    <mx:Script>
        <![CDATA[
            import flash.utils.describeType;
            import me.rkome.da.labs.Player;
            private function onCreationComplete():void
            {
                var player:Player = new Player();
                trace(describeType(player));
            }
        ]]>
    </mx:Script>
</mx:Application>

こんなアプリケーションを作ってみました。って事でビルドしてみましょう。

ビルドオプションはこんな感じ。

ビルドオプション

さて、結果はどう表示されるかというと。こんなん出ました。

<type name="me.rkome.da.labs::Player" base="Object" isDynamic="false" isFinal="false" isStatic="false">
  <extendsClass type="Object"/>
  <accessor name="test" access="readwrite" type="String" declaredBy="me.rkome.da.labs::Player">
    <metadata name="DarkOmeme">
      <arg key="" value="programmer"/>
    </metadata>
  </accessor>
</type>

オー、チャントDarkOmemeメタデータタグガフカサレテイルノガワカリマスネー。スゲーヤ。知ってるけどな!さっきやったから!

まー、あとはこのXMLを解析して煮るなり焼くなり、しましょうって事ですね。

次に、Flexでは有名なメタデータタグである[Bindable]を付加して同じようにdescribeTypeしてみました。そしたら、少し驚きだったんですよ。さっきね!

<type name="me.rkome.da.labs::Player" base="Object" isDynamic="false" isFinal="false" isStatic="false">
  <extendsClass type="Object"/>
  <implementsInterface type="flash.events::IEventDispatcher"/>
  <method name="addEventListener" declaredBy="me.rkome.da.labs::Player" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
    <parameter index="4" type="int" optional="true"/>
    <parameter index="5" type="Boolean" optional="true"/>
  </method>
  <method name="dispatchEvent" declaredBy="me.rkome.da.labs::Player" returnType="Boolean">
    <parameter index="1" type="flash.events::Event" optional="false"/>
  </method>
  <method name="hasEventListener" declaredBy="me.rkome.da.labs::Player" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
  <method name="removeEventListener" declaredBy="me.rkome.da.labs::Player" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
  </method>
  <method name="willTrigger" declaredBy="me.rkome.da.labs::Player" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
  <accessor name="test" access="readwrite" type="String" declaredBy="me.rkome.da.labs::Player">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange"/>
    </metadata>
    <metadata name="DarkOmeme">
      <arg key="" value="programmer"/>
    </metadata>
  </accessor>
</type>

なんと、IEventDispatcherが自動的に実装されてるじゃあ、ありませんか!自動的に!

どうやら、調べてみるとこれはmxmlc(Flexのコンパイラ)がメタデータタグを見つけてコードを自動生成するらしくて、これみたいなメタデータタグは今回の方法では作れないようです。

まあ、mxmlcはオープンソースなんで、オレオレmxmlcを作りましょうって事ですね。わかります。

今回はそこまで深入りしませんでした。

ただ、一応、mxmlcのソース(Javaで書かれている)を見に行ったんですが、どうやらコードを自動生成する部分はJavaでない、何やら良く分からないスクリプトで書かれていました
多分、テンプレートエンジンみたいのを備えていて、そいつに通すと自動生成されるんだと思います。

さて、本当はmxmlcのメタデータタグみたいなのが作れるといいなあと思ったんですが、思ったよりヘビーなんでこの方法で何か出来ないか模索してみることにします。

最後に。

Firefoxさんいつもお世話になっています。ありがとう。

 

読み込み中

クリックでキャンセルします

画像が存在しません

 

 

 

読み込み中

クリックでキャンセルします

画像が存在しません

 

 

試しにMXMLでメニューを作ってみた

NativeMenuをMXMLで定義した図

前置き

今、AIRでタスクトレイ常駐型のアプリを作ってます。
それでタスクトレイに常駐した際にタスクアイコンをクリックするとメニューが出るようにしたいと思って
処理を書いてたんですが、これが結構面倒くさい。

僕はある程度静的な処理は極力AS3じゃなくてMXMLで書きたいという、無類のMXMLフェチです。
なので、タスクトレイに常駐したアイコンを右クリックした時に出るNativeMenuをいちいちAS3で、addMenuだのaddSubmenuだのするのはあまり好きくないわけです。

そこで、MXMLでNativeMenuが定義できちゃうようなクラスを作っちゃおうと考えて調べてみました。

自分でMXMLタグを定義する方法

まず、カスタムMXMLタグを定義します。

いくつか方法はあります。

  1. カスタムコンポーネントを作る
    1. 既存のクラスを継承する
    2. UIComponentを継承して作る
    3. IUIComponentインターフェースを実装して作る(神の領域)
  2. 非ビジュアライズコンポーネントを作る
    1. 既存のクラスを継承する
    2. IMXMLObjectインターフェースを実装して作る

今回の場合、カスタムコンポーネントでNativeなメニューが作れないので、IMXMLObjectインターフェースを実装して定義することにしました。

仕様

Nativeなメニューを定義するMXML(イメージ)

<?xml version="1.0" encoding="utf-8"?>
<menu:MenuTree xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:menu="me.rkome.da.mxml.menu.*">
    <menu:menuList>
        <menu:MenuTreeItem label="表示" select="setVisible(true)" />
        <menu:Separator />
        <menu:MenuTreeItem label="終了" select="onTerminate()" />
    </menu:menuList>
</menu:MenuTree>

こんな感じにNativeなメニューをSystemTrayMenu.mxmlというファイルにして定義できればいいなあと思います。

MenuTreeというのがメニューのグループになっていて、このクラスの子要素としてMenuTreeItemを書くと
メニューのラベルとクリックされた時のイベント内容を定義できるようになっています。

labelプロパティが表示する文字で、selectイベントがメニューがクリックされた時のイベントです。

Separatorはメニューラベル間を区切る為のメニューアイテムです。

こんな感じのMXMLを書いて、MenuTreeのインスタンスを使って、getMenu()とか呼び出すだけで
MXMLのツリー構造の通りのNativeなメニューが作れたら便利じゃーんというのが今回の仕様です。

実際にMXMLタグを作ってみた

さて、ではMXMLタグを定義する方法です。

FlexにはIMXMLObjectっていうinterfaceがあって、これを実装したクラスはコンポーネントじゃなくてもMXMLで記述できるようになるようです。

mx.core.IMXMLObject (Flex 3.2)
http://livedocs.adobe.com/flex/3_jp/langref/mx/core/IMXMLObject.html
IMXMLObjectの実装について
http://livedocs.adobe.com/flex/3_jp/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001702.html

まあ、これくらいは無類のMXMLフェチの名乗るくらいなので知っています。確認です。

MXMLでたとえばListタグの子要素として直接dataProviderの情報を書けたりするあれ。普通なら<mx:dataProvider></mx:dataProvider>で囲まないといけないのに、なんでーとか思ってたら、どうやら[DefaultProperty]っていうメタデータタグがあるらしい。
あと、コンポーネントのビヘイビアを記述するとき、Flex Builderで出てくる候補リストにはFadeとかMoveとかエフェクト関連しか出てこないのは、これもどうも[ArrayElementType]っていうメタデータタグのおかげらしい。

メタデータタグか・・。じゅるり。

さて、メタデータタグフェチになる前にとりあえずMXMLでNativeMenuを書けるようにしてみましょう。

MenuTreeもMenuTreeItemもSparatorも同等に扱えるように、メニューになりえるものが持っている共通項、インターフェースを定義してみる。

IMenuTree.as

package me.rkome.da.mxml.menu
{
    import flash.display.NativeMenuItem;
   
    import mx.core.IMXMLObject;
   
    public interface IMenuTree extends IMXMLObject
    {
        function getMenu():NativeMenuItem;
        function get label():String;
    }
}

 labelは分かりますね。メニューに表示する文字列です。

getMenu()関数はNativeMenuItemを返します。もしNativeMenuItemを複数持つような場合はsubmenuプロパティを参照してもらうようにすれば
NativeMenuもNativeMenuItemもカバーできるかなーっていう適当仕様。

まあ、日本語よりもソースコードのが分かりやすいという病気の人の為に(僕の日本語が下手なだけ)どんどんコードを載せます。

MenuTree.as

package me.rkome.da.mxml.menu
{
    import flash.display.NativeMenu;
    import flash.display.NativeMenuItem;
   
    import mx.core.IMXMLObject;

    [DefaultProperty("menuList")]
    /**
     * Nativeなメニューを定義する為のMXMLタグ
     * このタグをルートにメニューを定義して、getNativeMenu()を呼び出すと
     * NativeMenuが生成される
     *
     * @author DarkOmeme
     *
     */

    public class MenuTree implements IMenuTree
    {
        public function MenuTree()
        {
        }

        public function initialized(document:Object, id:String):void
        {
        }
       
        private var _label:String;
        private var _menuList:Array;

        [ArrayElementType("me.rkome.da.mxml.menu.IMenuTree")]
        /**
         * メニューアイテム(子要素)
         * デフォルトのプロパティで、IMenuTreeが実装されたクラスの配列
         * @return
         *
         */
   
        public function get menuList():Array
        {
            return _menuList;
        }
        public function set menuList(value:Array):void
        {
            _menuList = value;
        }

        /**
         * メニューを生成するための関数
         * IMenuTree で定義されている
         * @return
         *
         */
           
        public function getMenu():NativeMenuItem
        {
            var menu:NativeMenu = new NativeMenu();
            for each (var item:IMenuTree in _menuList)
            {
                var menuItem:NativeMenuItem = item.getMenu();
                var subMenu:NativeMenu = menuItem.submenu;
                if (item.getMenu().submenu != null )
                {
                    menu.addSubmenu( subMenu, item.label );
                }
                else
                {
                    menu.addItem( item.getMenu() );
                }
            }
            var root:NativeMenuItem = new NativeMenuItem(_label);
            root.submenu = menu;
            return root;
        }

        /**
         * 自分が子要素を持たない時に呼ばれるメニュー生成用関数
         * @return
         *
         */
   
        public function getNativeMenu():NativeMenu
        {
            var item:NativeMenuItem = getMenu();
            return item.submenu;
        }

        /**
         * メニューのラベル
         * ルート要素の場合、この値に意味は持たない
         * (toolTipに表示されてもいいかもね)
         * IMenuTree で定義されている
         * @param value
         *
         */
   
        public function set label(value:String):void
        {
            _label = value;
        }
        public function get label():String
        {
            return _label;
        }
    }
}

デフォルトでタグの子要素がmenuListになるようになってます。

但し、mxmlファイルとして別ファイルで定義する場合、DefaultPropertyメタデータタグが利いてくれません。
ってことで、別のMXMLファイルで別途定義する場合はちゃんとmenuListというプロパティを指定してタグを書くようにしましょう。
(さっきのイメージは別のMXMLファイルで定義してある想定のMXMLソースでした)

MenuTreeItem.as

package me.rkome.da.mxml.menu
{
    import flash.display.NativeMenu;
    import flash.display.NativeMenuItem;
    import flash.events.Event;
    import flash.events.EventDispatcher;
   
    import mx.core.IMXMLObject;

    [Event(name="select", type="flash.events.Event")]
    /**
     * NativeMenuItemの役割を果たすクラス
     *
     * @author DarkOmeme
     *
     */

    public class MenuTreeItem extends EventDispatcher implements IMenuTree
    {
        public function MenuTreeItem()
        {
        }

        public function initialized(document:Object, id:String):void
        {
        }
       
        /**
         * submenuのない、NativeMenuItemを返す
         * クリックされた時のイベントをdispatchする為に、イベントハンドラを設定してます
         * @return
         *
         */
   
        public function getMenu():NativeMenuItem
        {
            var menuItem:NativeMenuItem = new NativeMenuItem(_label);
            menuItem.addEventListener(Event.SELECT, onSelect);
            return menuItem;
        }
       
        private var _label:String;

        public function set label(value:String):void
        {
            _label = value;
        }
        public function get label():String
        {
            return _label;
        }

        /**
         * クリックされたら、そのままdispatchEventでイベント通知
         * @param evt
         *
         */
   
        private function onSelect(evt:Event):void
        {
            dispatchEvent(evt);
        }
    }
}

 

クリックされた事を知る為に、selectイベントを通知するようにしてあります。
ここでもEventメタデータタグが大活躍。書いておくと、MXMLで書くときにFlex Builderで候補が出てくるようになります。

次回は絶対メタデータタグでなんかしたい。

Separator.as

 package me.rkome.da.mxml.menu
{
    import flash.display.NativeMenuItem;

    public class Separator implements IMenuTree
    {
        public function Separator()
        {
        }
       
        public function initialized(document:Object, id:String):void
        {
           
        }

        public function getMenu():NativeMenuItem
        {
            return new NativeMenuItem("", true);
        }
       
        public function get label():String
        {
            return null;
        }
    }
}

ほとんど、説明不要ですが。
getMenu()関数ではセパレータを返します。

と言う感じで、これで一通りMXMLタグを作りました。

これでイメージ通り書けるのか?!

その結果は、ソースを落として実際に確認してみてください。

で、このポストの冒頭のスクリーンショットが結果です。

NativeMenuをMXMLで定義した図

コードも一緒に収めたんで少し画像が大きいです。

MenuTreeApp ソースコー [ zip ]

ふいー、ようやく、一個記事がかけた。

気付けば9月

しかも、もう既に3日も経ってるっていう。

内心ポルナレフにもなりますよ。

8月こそは変態になろうと思ってたんですけどね…。

で、とりあえず最近、ゲームの仕事やら同人誌制作やらで忙しかったんで、自分が個人的にやるプログラミングが無かったんですが、9月に入って落ち着いたということで。

僕はブログを書くという習慣がどうやら無い。
厳密に言えば、『なんでも』ブログに書く習慣だね。
もっと言えば、僕はネット上で会話するとか、コミュニケーションするとか、知り合いになるとか、そういうやつができない。

まあ、それは中学の時に発症した病気を今も引きずったような事を不特定多数に向けて発信する恐怖からなんですが。

しかし、ほら、プログラマーがこの先生きのこるには、ブログとか書いてさ、自分が作ったすごいものを挨拶程度に公開したりさ、勉強会の一つも主催したりさ、そういうのをやるべきだ、という強迫観念もあるんですよ。

という事で、とりあえず、その第一歩としてなんでもブログを書くことを習慣づけたい。

今日書きたい事は、8月に予定していて出来なかった、変態になる計画かな。
まあ、最近、Flashプログラミング、敢えてFlexプログラミングと言わせて欲しい。
これを軸にして、今更色々やってみたい。

変態1年生ができる事を列挙してみます。

  1. カスタムスキン
  2. カスタムコンポーネント
  3. カスタムメタデータタグ
  4. 他言語連携
  5. 組み込み言語とVM on Flash
  6. モジュール
  7. Spark Project のライブラリ研究
  8. オレオレFlashPlayer

こんなところかな。 よーし、今月からパパ頑張っちゃうぞ。

作業中メモ 2009-08-25

マニフェストファイルの書き方
http://d.hatena.ne.jp/arkw/20070516/1179296044

[ExcludeClass]、[Exclude]の使い方
http://www.matzmtok.com/blog/?p=11

カスタムコンポーネント内でデザインモードかどうかを知る
http://www.anychart.com/blog/2008/02/29/creating-custom-design-time-preview-for-flex-3-components/

2009-06-29 の 教訓

Error #2015: BitmapData が無効です。

BitmapDataの幅か高さが規定範囲外の時に出る。

規定範囲は[0, 2880] pxね。これより大きかったり、小さかったりするとこのエラーが出るらしい。

本日の救世主様リンク
http://www.milk-garden.net/blog/?p=619

MEXSLTをspark projectにコミットしてみた

明日ってのは、確かに地球の自転周期から言えば、24時間かもしれないがね
日光・鬼怒川の自転周期から言えばもっと長いのだよ。

すみません。
週末、鬼怒川に温泉入りに言っててすっかりブログが更新できませんでした。

で、一週間が過ぎましたが、ついにspark projectに自分の作ったライブラリをコミットしましたよ!

MEXSLT

このライブラリは、Flexユーザー向けのXML解析サポートライブラリとでも言いましょうか。

XSLTっていう、XMLを別のXMLやらHTMLやらに変換するマークアップ言語があるんですが、それを参考にして
FlashでXMLを読み込んで、それを自分で定義したクラスに変換したりできるものを作りました。

サンプルとして、こんなXMLを読み込むとします。
ちなみに、このXMLはなんちゃって個人情報です。

<?xml version="1.0" encoding="UTF-8"?>
<records>
  <record>
    <name>宇多田 信輔</name>
    <ruby>うただ しんすけ</ruby>
    <mail>utada_shinsuke@example.com</mail>
    <sex></sex>
    <age>65</age>
    <birthday>1944/1/1</birthday>
    <married>既婚</married>
    <bloodtype>A型</bloodtype>
    <prefecture>埼玉県</prefecture>
    <curry>ぶっかけ・せき止め派</curry>
  </record>
  <record>
    <name>竹下 未來</name>
    <ruby>たけした みらい</ruby>
    <mail>takeshita_mirai@example.com</mail>
    <sex></sex>
    <age>24</age>
    <birthday>1984/10/12</birthday>
    <married>既婚</married>
    <bloodtype>A型</bloodtype>
    <prefecture>新潟県</prefecture>
    <curry>ぶっかけ・せき止め派</curry>
  </record>
  <record>
    <name>北村 翔太</name>
    <ruby>きたむら しょうた</ruby>
    <mail>kitamura_shouta@example.com</mail>
    <sex></sex>
    <age>37</age>
    <birthday>1972/1/8</birthday>
    <married>既婚</married>
    <bloodtype>O型</bloodtype>
    <prefecture>神奈川県</prefecture>
    <curry>手前ルー・せき止め派</curry>
  </record>
  …
</records>

このXMLを読み込んで、自分で定義したクラスにそれぞれの値を設定したりする作業って割とよくあると思うんですよ。
そこらへんを、MXMLを使って簡単に書けたらいいなという目論見で作ったライブラリの使用例がこちら。

(例1)

  1. <mex:MEXSLT id="parser" output="array">
  2.   <mex:xslt>
  3.     <mex:Template match="records/record">
  4.       <mex:New method="push" product="{DummyData}">
  5.         <mex:ValueOf select="name" target="name" />
  6.         <mex:ValueOf select="ruby" target="ruby" />
  7.         <mex:ValueOf select="mail" target="mail" />
  8.         <mex:ValueOf select="sex" target="sex" />
  9.         <mex:ValueOf select="age" target="age" />
  10.         <mex:ValueOf select="birthday" target="setBirthday" method="invoke" />
  11.         <mex:ValueOf select="married" target="setMarried" method="invoke" />
  12.         <mex:ValueOf select="bloodtype" target="bloodType" />
  13.         <mex:ValueOf select="prefecture" target="prefecture" />
  14.         <mex:ValueOf select="curry" target="curry" />
  15.       </mex:New>
  16.     </mex:Template>
  17.   </mex:xslt>
  18. </mex:MEXSLT>

mexってのは名前空間です。あらかじめ、xmlns:mex="http://da.rkome.me/2009/mexslt"というようにmexという名前空間を設定しておいてください。

例えば、<Application>の直下でこのXMLパーサの定義を行うなら、<Application xmlns:mex="http://da.rkome.me/2009/mexslt">という感じで。

まず、一番上のMEXSLTタグ。これは、XMLパーサの定義です。
output属性には、このパーサがどのような形式を返すかを指定します。arrayかobjectのどちらかです。
そして、このパーサがどのようにXMLを解析するのかを<mex:xslt>ノード以下に書きます。

ここからは、xsltプロパティの設定の仕方。

まず、Templateという大枠の定義を書きます。
match属性に、渡されたXMLのどのタグを元にインスタンスを生成するかをXPathで指定します。
このサンプルの場合は、recordsタグの子要素のrecordタグ以下の値を一つのクラスにまとめます。

一応、クラス定義はこんな感じ。

  1. package me.rkome.da.sample.model
  2. {
  3.   public class DummyData
  4.   {
  5.     public function DummyData()
  6.     {
  7.     }
  8.  
  9.     public var name:String;
  10.     public var ruby:String;
  11.     public var mail:String;
  12.     public var sex:String;
  13.     public var age:Number;
  14.     public var birthday:Date;
  15.     public var married:Boolean;
  16.     public var bloodType:String;
  17.     public var prefecture:String;
  18.     public var curry:String;
  19.    
  20.     public function setBirthday(dateString:String):void
  21.     {
  22.       var array:Array = dateString.split("/");
  23.       birthday = new Date(parseInt(array[0]), parseInt(array[1]), parseInt(array[2]));
  24.     }
  25.    
  26.     public function setMarried(marriedString:String):void
  27.     {
  28.       married = (marriedString == "既婚");
  29.     }
  30.    
  31.     public function toString():String
  32.     {
  33.       return "名前: " + this.name + "n" +
  34.           "よみ: " + this.ruby + "n" +
  35.           "メール: " + this.mail + "n" +
  36.           "性別: " + this.sex + "n" +
  37.           "歳: " + (this.sex == "女" ? this.age2 : this.age) + "n" +
  38.           "生年月日: " + this.birthday.toDateString() + "n" +
  39.           "結婚: " + (this.sex == "女" && !this.married && 30 <= this.age ? "募集中" : this.married) + "n" +
  40.           "血液型: " + this.bloodType + "n" +
  41.           "出身: " + this.prefecture + "n" +
  42.           "カレーの食べ方: " + this.curry;
  43.     }
  44.   }
  45. }

このクラスへと変えるために、まずNewタグというのをTemplateタグの直下に書きました。
これは、match属性でマッチしたXMLからクラスを生成する時に使用するタグです。

method属性には生成したインスタンスを出力オブジェクトに対してどうするかを指定します。
サンプルの場合、出力オブジェクトはarrayなのでここではpushを指定しています。
例えば、出力オブジェクトがobjectだった場合、Newタグのtarget属性に設定先プロパティ名、method属性にassignを指定するとtarget属性で指定したプロパティに生成したインスタンスを代入します。

product属性には、生成するインスタンスのクラス名を設定します。{}で囲んでいるのは何故かというと、product属性の値はClass型だからです。

で、Newタグの直下にずらりと書いてあるのがValueOfタグで、これはNewタグで生成したクラスに値を設定するためのタグです。

特別なクラスを生成しないで、単にString型の配列を作りたいときは、Templateタグの直下にValueOfオブジェクトを書けばOKです。

例えば、このなんちゃって個人情報の名前の配列を受け取りたい場合はこんな感じ。

(例2)

  1. <mex:MEXSLT id="parser" output="array">
  2.   <mex:xslt>
  3.     <mex:Template name="nameList" match="records/record">
  4.       <mex:ValueOf select="name" method="push" />
  5.     </mex:Template>
  6.   </mex:xslt>
  7. </mex:MEXSLT>

さて、ValueOf タグの属性の説明。
select属性にTemplateタグで指定したXMLに対して、XPathでタグを指定します。
この例2の場合は、Templateタグのmatch属性にrecords/recordがあり、ValueOfタグのselect属性にnameがあるため、recordsタグの子要素のrecordタグの子要素のnameタグの値を指定していることになります。

method属性にはassign、push、invokeを指定できます。assignは代入、pushは配列に追加、invokeはtarget属性で指定した名前の関数をselect属性で指定した値を引数として呼び出します。
例1でinvokeを指定しているValueOfタグのtarget属性にはsetBirthdayとかsetMarriedといった関数の名前が書いてあります。
この二つはどちらもString型を引数に取る関数で、内部ではそれぞれ値をDate型やBoolean型に変換しています。
method属性のデフォルト値はassignなので、プロパティにselect属性で指定した値を代入する場合はmethod属性をいちいち設定しなくてもassignが設定されています。

この例には出てきませんが、ValueOfタグにはもう二つ重要な属性があります。
一つは、defaultValue属性です。select属性で指定した値がXML文書の中に記述されてなかった場合に設定する値を書くと、この属性で指定した値が設定されます。
もう一つは、required属性です。これもselect属性で指定した値がなかった場合の動作で、required属性をtrueに設定するとMEXSLTErrorをスローするようになります。デフォルトはfalseになっているので、必須のものにだけrequired属性をtrueに設定してください。

最後に、このように定義したMEXSLTクラスを実際に使う時です。

  1. var result:Array = parser.parse(new XML(xml));
  2. for each (var data :D ummyData in result)
  3. {
  4.   println(data.toString());
  5.   println("================================");
  6. }

parse関数でXMLを指定すれば、解析して戻り値として結果を返します。

required属性をtrueに設定した場合など、エラーがスローされる可能性がある場合はtry~catchでMEXSLTErrorをcatchするようにしてください。

また、複数のXMLパーサの定義を行いたい場合は、Templateをいくつも定義してTemplateタグのname属性に一意の名前をつけてcallTemplate関数でその名前を指定することにより、解析することが出来ます。

  1. var names:Array = parser.callTemplate("nameList", new XML(xml));
  2. for each (var name:String in names)
  3. {
  4.   println(name);
  5.   println("================================");
  6. }

導入方法

導入は、一番簡単なのはMEXSLT.swcをライブラリパスとしてFlexプロジェクトに追加します。

MEXSLT.swcはas3/MEXSLT/MEXSLT/binにあります。

次に、名前空間を書いてください。

Flexプロジェクトを作ると、大抵Applicationタグがルートになるはずなので、mx名前空間の次にでもmex名前空間に以下のURLで設定してください。

xmlns:mex="http://da.rkome.me/2009/mexslt"

これでMEXSLTを使えるようになるはずです。

もし分からなかったら、気軽に僕にメールを下さい。このブログにコメントして頂いても結構です。
ある程度サポート致します。

と言うわけで、鬼怒川から帰ってきたDarkOmemeはウラシマ効果によって、もう眠いわけです。普段なら3時まで平気で起きているのに、今日はまだ2時だというのに半分寝てます。

ではでは、おやすみなさい。

先日のリングコマンドの不具合について

どうにも気持ち悪かったんで、先日アップしたリングコマンドの不具合について調べてました。

どうやら、僕がUIComponentにBitmapをaddChildして使う際に行った実装がまずかったみたいです。

UIDecorator.as 

  1. public class UIDecorator extends UIComponent
  2. {
  3.   public function UIDecorator(displayObject:DisplayObject)
  4.   {
  5.     super();
  6.     BindingUtils.bindSetter(bindCenter, this, "centerX");
  7.     BindingUtils.bindSetter(bindCenter, this, "centerY");
  8.     this.displayObject = displayObject;
  9.     super.addChild(this.displayObject);
  10.   }
  11.  
  12.   [Bindable] public var centerX:Number = 0;
  13.   [Bindable] public var centerY:Number = 0;
  14.  
  15.   private function bindCenter(dummy:Number):void
  16.   {
  17.     this.lx = this.lx;
  18.     this.ly = this.ly;
  19.   }
  20.  
  21.   [Bindable]
  22.   public function get lx():Number
  23.   {
  24.     return super.x + centerX;
  25.   }
  26.   public function set lx(value:Number):void
  27.   {
  28.     super.x = value – centerX;
  29.   }
  30.  
  31.   [Bindable]
  32.   public function get ly():Number
  33.   {
  34.     return super.y + centerY;
  35.   }
  36.   public function set ly(value:Number):void
  37.   {
  38.     super.y = value – centerY;
  39.   }
  40.  
  41.   public override function set width(value:Number):void
  42.   {
  43.     super.width = value;
  44.     displayObject.width = value;
  45.   }
  46.   public override function set height(value:Number):void
  47.   {
  48.     super.height = value;
  49.     displayObject.height = value;
  50.   }
  51.  
  52.   public var displayObject:DisplayObject;
  53. }

こんな感じに実装してみた。
これは正解のソースで、本当はコンストラクタの中でdisplayObjectの幅と高さをthisの幅と高さにバインドする処理が入ってました。

で、このバインドを信用していたんだけど、どうもビルドするたびに、このバインドが利いたり利かなかったり・・・。
もう、なんでこんな曖昧なんだ。。バインド。。一気に僕の信用を落としました。

さて、で、これではBitmapをまだaddChildしてないので、ちゃんとBitmapをaddChildするようにコレを継承して、こんなのを作りました。

UIBitmap.as

  1. public class UIBitmap extends UIDecorator
  2. {
  3.   private var _bitmap:Bitmap;
  4.   public function UIBitmap(bitmapData:BitmapData=null)
  5.   {
  6.     super(new Bitmap());
  7.     _bitmap = this.displayObject as Bitmap;
  8.     this.bitmapData = bitmapData;
  9.   }
  10.  
  11.   public function set bitmapData(value:BitmapData):void
  12.   {
  13.     _bitmap.bitmapData = value;
  14.     if (value == null)
  15.       return;
  16.     this.width = value.width;
  17.     this.height = value.height;
  18.   }
  19.   public function get bitmap():Bitmap
  20.   {
  21.     return _bitmap;
  22.   }
  23. }

このソースも正解のソース。
本当はbitmapDataのsetterの中でthisの幅と高さを入れる処理はしてなかった。

まあ、つまり、UIComponentに入れたBitmapのサイズがバインド処理で行うはずなのに行われてなかったというものでした。

おわり。

明日は、MXMLで書くXMLパーサを作った話を書く予定。

リングコマンドを作ってみた

先日書いた、MEFrameworkを使いながらリングコマンドを作ってみた。 

Read more…

作業中メモ 2009-03-18

Flexでちょっと実用的なサンプル・サイトを作ってみる(モジュール編)
http://itpro.nikkeibp.co.jp/article/COLUMN/20080205/292979/

Flex Builder でのキーボードショートカット
http://www.adobe.com/livedocs/flex/201_jp/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=ui_reference_047_35.html

これ知らなかったから、時々デバッグ実行しようとして間違えてプロファイル実行してイラッ☆ってしてた。
なんか、プロファイル実行間違って押しちゃうと、Flex Builder再起動しないといけなくないですか?

Custom Metadata in AS3
http://www.nankaifactory.com/blog/2008/03/custom-metadata-in-as3.html
http://www.nankaifactory.com/blog/2008/03/custom-metadata.html