kagamihogeの日記

kagamihogeの日記です。

Flex の localToGlobal の使いどころ

flash.display.DisplayObject#localToGlobal(point:Point):Point - Adobe Flex 3.2 リファレンスガイド によると「point オブジェクトを表示オブジェクトの (ローカル) 座標からステージ (グローバル) 座標に変換します。」とかいう機能を提供してくれるこのメソッド。その出番は何時なのか。

まずは、試しにこんな感じに絶対座標でコンポーネントを配置してみる。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
        <![CDATA[
            import mx.controls.Menu;
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            private function menuButtonClickHandler(event:MouseEvent):void {
                Alert.show("x=" + menuButton.x + ":y=" + menuButton.y);//x=10:y=60 と表示;
            }
        ]]>
    </mx:Script>
    <mx:Canvas x="60" y="40" width="200" height="120">
        <mx:Button id="menuButton" x="10" y="60" label="ボタン" click="menuButtonClickHandler(event)"/>
    </mx:Canvas>
</mx:Application>

コード中のコメントにあるとおり menuButton の x と y は 10,60 と表示される。これは親コンポーネントである Canvas を基準にした座標なことがわかる……とまぁ、x,y のプロパティは親となるコンテナコンポーネントから見ての座標なわけです。なお Flex の座標系の用語については Flex の座標系 - MouseEvent#localX と Canvas#contentMouseX のちがい - kagamihogeのblog を参照。

これだと困るケースというのは、たとえば、 みたいにボタンの下にメニューを表示したい、というとき。ボタン(この例では menuButton のこと)の x,y をそのまま使うと、Flex アプリケーション全体から見た絶対座標の位置で表示されてしまう。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
        <![CDATA[
            import mx.controls.Menu;
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            private function menuButtonClickHandler(event:MouseEvent):void {
                var myMenu:Menu;
                myMenu = Menu.createMenu(null, [{label:"メニュー1"},{label:"メニュー2"}]);
                myMenu.show(
                    menuButton.x,
                    menuButton.y + menuButton.height); //10,60の位置にメニューが表示される!
            }
        ]]>
    </mx:Script>
    <mx:Canvas x="60" y="40" width="200" height="120">
        <mx:Button id="menuButton" x="10" y="60" label="ボタン" click="menuButtonClickHandler(event)"/>
    </mx:Canvas>
</mx:Application>

こんな感じのコードを実行すると、下図のようにわけのわからん位置にメニューが表示される。x=10,y=60 の位置に表示しているから、わけのわからない位置に見える、という話なのだけども。

というわけで。こういう事態に対処する場合に localToGlobal を使用する。コードは↓みたいな感じ。localToGlobal のターゲットとなるオブジェクトは親コンポーネントを使うのがミソといえばミソだろうか。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
        <![CDATA[
            import mx.controls.Menu;
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            private function menuButtonClickHandler(event:MouseEvent):void {
                var localPoint:Point = new Point(menuButton.x, menuButton.y);
                var globalPoint:Point = hogeCanvas.localToGlobal(localPoint);

                Alert.show("x=" + globalPoint.x + ":y=" + globalPoint.y);//x=70:y=100 と表示
                var myMenu:Menu;
                myMenu = Menu.createMenu(null, [{label:"メニュー1"},{label:"メニュー2"}]);
                myMenu.show(
                    globalPoint.x,
                    globalPoint.y + menuButton.height);
            }
        ]]>
    </mx:Script>
    <mx:Canvas id="hogeCanvas" x="60" y="40" width="200" height="120">
        <mx:Button id="menuButton" x="10" y="60" label="ボタン" click="menuButtonClickHandler(event)"/>
    </mx:Canvas>
</mx:Application>