AIRが持つ充実したウィンドウAPI

ブラウザ上で動くFlashと違い、デスクトップアプリケーションの実行環境であるAIRは、「自分のウィンドウ」というものを持っており、ブラウザの枠を取り払われた表現の自由を獲得した。しかも、AIRはそれに留まらない。OSネイティブのAPIを使用した時のような、きめ細やかなウィンドウ制御を行うことも可能だ。今回は、AIRのそうしたウィンドウAPIを見ていくことにしよう。

AIRのβ版のウィンドウAPIが持つ機能を一覧にすると以下のようになる。

  • ウィンドウを新しく作成することが可能
  • ウィンドウが閉じられた、移動されたなどのイベントを捕捉し、処理することが可能
  • ウィンドウの最大化/最小化、移動やリサイズなど、ウィンドウの状態をプログラムから制御することが可能
  • タイトルバーの表示可否、タスクバーにウィンドウが表示されるかどうか、などネイティブ環境に依存する部分も制御可能
  • 背景が透明なウィンドウを作成可能。これを応用すると、矩形に縛られない自由な形状のウィンドウを作ることができる
  • ウィンドウのフルスクリーン表示が可能

また、β版でサポートされていない機能は以下の通りだ。

  • Windowsにおけるウィンドウのツールバー、Mac OS Xのツールバーやプロキシアイコン
  • システムトレイへのアイコン表示
  • アプリケーションのアイコンを操作
  • デスクトップスクリーンの情報取得
  • ネイティブウィンドウメニュー

これらの機能に関しては、AIR 1.0の正式リリース時に、フォローアップの記事をお届けできるとよい、と考えている。

AIRが持つウィンドウAPIの概要

さて、AIRプログラミングにおいてウィンドウを作成するには、大きく分けて二種類の方法がある。

一つは、JavaScriptプログラミングでお馴染みのwindow.open()関数である。HTML/JavaScriptを用いてAIRアプリケーションを作成する際はこちらの方法を使うことができる。window.open()で作成したウィンドウには、JavaScriptからしかアクセスすることはできず、DOMを用いてウィンドウのコンテンツにアクセスすることになる。クローム(Windowsのタイトルバーに代表されるウィンドウの枠の事)は、OSネイティブのシステムクロームしか使用することはできない。……などといろいろ制限の多いウィンドウであるが、例外的にwindow.htmlControl.paintsDefaultBackgroundプロパティをfalseに設定することでウィンドウの背景を透明化することだけは出来る。しかし、当連載はHTML/JavaScriptを用いたAIRプログラミングは対象の範囲外なので、ここではこれ以上触れないこととする。

もう一つは、flash.display.NativeWindowクラスを用いる方法だ。Flexを用いてAIRアプリケーションを作成する際には、知っておくと便利なクラスだ。アプリケーションのメインウィンドウも含めた全ての「ウィンドウ」を表すクラスで、JavaScriptからも利用することができる(JavaScriptではwindow.runtime.flash.display.NativeWindowクラスを用いる)。今回紹介するサンプルアプリケーションは、NativeWindow APIについて解説するためのものである。

サンプルアプリケーションによる解説

今回はNativeWindow APIの解説のため、APIが持つほぼ全ての要素を網羅したサンプルアプリケーションを用意した。以下がそのサンプルアプリケーションで、「ウィンドウ作成」ボタンをクリックするとウィンドウが立ち上がる。チェックボックスはそのラベルの通り、チェックを入れた状態でウィンドウを作成するとフルスクリーンでウィンドウが表示される。また、作成したウィンドウは、マウスのドラッグにより移動することができる。さらに、ウィンドウ上でESCAPEキーを押すとウィンドウが閉じる。

サンプルアプリケーション。「ウィンドウ作成」ボタン(左画面)をクリックすればウィンドウ(右画面)が立ち上がる。

サンプルのソースコードを単純にするために、ウィンドウの様々な設定変更を行うためにはソースコードを直接書き換える必要があるようにしている。 例えば、背景を透明にしたウィンドウを作成するようソースを書き変えて実行した結果は、以下のように「四角じゃない」ウィンドウ(ピンクの丸のこと)が作成される。上のサンプルと見比べてほしい。

背景を透明にして作成したウィンドウ。非矩形のウィンドウを作成することが可能だ。

このサンプルを用いて、今回と次回の2回にわたりAIRのウィンドウAPIについて説明していきたい。以下にそのソースコードを示す。

AIRWindowExample.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" closing="onClosing(event);">
    <mx:Script>
        <![CDATA[
            import mx.core.Application;
            import flash.utils.*;

            // (1) 新しく生成するウィンドウを格納する変数
            [Bindable]
            private var win:NativeWindow;

            // ウィンドウ生成ボタン押下時の処理
            private function createWindow():void {
                // ウィンドウを複数生成しない
                if (win != null) return;

                // (2) ウィンドウの初期設定を行い、ウィンドウの生成
                var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions();
                initOptions.systemChrome = NativeWindowSystemChrome.STANDARD;
                initOptions.transparent = false;
                initOptions.type = NativeWindowType.UTILITY;
                win = new NativeWindow(false, initOptions);

                // ウィンドウの幅と高さ、タイトルをセット
                win.height = 300; win.width = 300; win.title = "サンプルウィンドウ";

                // ウィンドウの内容を作成
                var winContent:Sprite = new Sprite();
                var g:Graphics = winContent.graphics;
                g.beginFill(0xFF99CC, 0.8);
                g.drawCircle(win.width/2, win.height/2, win.height/2);
                g.endFill();
                win.stage.addChild(winContent);
                // (3) フルスクリーンでウィンドウを表示
                if (fullScreen.selected) {
                    win.stage.displayState = StageDisplayState.FULL_SCREEN;
                }
                // ウィンドウを可視化
                win.visible = true;

                // (4) 以下は、ウィンドウにイベントリスナを紐付けている
                win.addEventListener(Event.CLOSE, function(event:Event):void {
                    win = null;
                });
                win.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void {
                    // ESCAPEキーだったらウィンドウを閉じる
                    if (e.keyCode == 27) {
                        win.close();
                    }
                });
                win.stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
                    // (5) ウィンドウを移動
                    win.startMove();
                });
            }
            // (6) メインウィンドウが閉じようとしている時のイベント処理。
            //     mx:WindowedApplicationのclosing属性で指定されている。
            private function onClosing(event:Event):void {
                // (7) デフォルトのイベント処理(ウィンドウが閉じる)を中断
                event.preventDefault();
                var mainWindow:WindowedApplication = this;
                // 0.1秒ごとにalpha値をマイナスしていき、0になったらアプリ終了
                var timerId:uint = setInterval(function():void {
                    if ((mainWindow.alpha -= .2) <= 0) {
                        clearInterval(timerId);
                        // (8) アプリ終了
                        Shell.shell.exit(0);
                    }
                }, 100);
            }
        ]]>
    </mx:Script>
    <mx:Button x="31" y="36" label="ウィンドウ作成" click="createWindow();" enabled="{win == null}"/>
    <mx:CheckBox id="fullScreen" label="フルスクリーン" x="133" y="36"/>
</mx:WindowedApplication>

対応するアプリケーションディスクリプタファイルの内容は以下のようになる。このファイルの内容に関しては前回の記事を参照していただきたい。

AIRWindowExample-app.xml

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.0.M4" appId="AIRWindowExample" version="1.0 Beta">
    <name>AIRWindowExample</name>
    <!-- システムクローム、透明度は、さまざまに変更してみていただきたい -->
    <rootContent systemChrome="none" transparent="true" visible="true">AIRWindowExample.swf</rootContent>    
</application>

最後にアプリケーションのメインウィンドウについて

今回の解説の最後に、アプリケーションのメインウィンドウについて説明しておきたい。アプリケーションを起動して表示されるウィンドウは、AIRのランタイムによって自動的に生成されるものだ。そのメインウィンドウに対して初期設定を行うには、アプリケーションディスクリプタファイルのrootContent要素を使用する。アプリケーションディスクリプタとrootContent要素については前回の記事を参考にしてほしい。上記のサンプルコードも参照していただきたい。

ウィンドウを生成する際、クロームをなしにする(systemChrome="none")と、タイトルバーやウィンドウ周りの枠線などが一切表示されなくなる。しかし、今回のアプリケーションのように、MXMLファイルのルート要素としてmx:WindowedApplication要素を用いると、Flex用のクロームが表示されるようになる

mx:WindowedApplicationによるFlexクロームが付与された同サンプル。最初の画面と見比べてみてほしい。

メインウィンドウに関してもクロームを一切表示しないようにするには、ルート要素にmx:Applicationを指定してほしい。

クロームなしで、mx:Applicationをルート要素に持つメインウィンドウ

また、アプリケーションのメインウィンドウを表すNativeWindowのインスタンスにアクセスするには、MXMLファイル上ではthis.stage.windowを、JavaScriptではwindow.nativeWindowを用いることができるということも、知っておくとよいだろう。

今回の解説はここまでだ。サンプルアプリケーションについての詳細な解説は次回行うこととする。