Adobe AIRで作るデスクトップアプリケーション

第6回ウィンドウの操作

ウィンドウの外観

ウェブ上のFlashコンテンツと違い、AIRアプリケーションにはそれぞれのウィンドウがあります。デフォルトの状態ではOSのウィンドウと同じ外観を持ったシステムクロームが使われます。開発環境に関係なく、アプリケーションを実行しているプラットフォームのウィンドウになります。

MacintoshとWindowsのシステムクローム
MacintoshとWindowsのシステムクローム

これはアプリケーション記述ファイルの設定によるものです。rootContent要素のsystemChrome属性が"standard"であればシステムクロームを指定していることになります。

<rootContent systemChrome="standard" transparent="false" visible="true">[SWF reference is generated]</rootContent>

システムクロームを使わない場合はsystemChrome属性を"none"にします。すると、Flexクロームに変わります。デフォルトのMXMLではルートにWindowedApplicationコンポーネントが指定されているため、そのカスタムクロームが適用されるのです。ただし、systemChrome属性を"none"にしただけではウィンドウのコーナーが不透明で違和感があります。これを解消するには、transparent属性を"true"にしてウィンドウのアルファサポートを有効にします。

<rootContent systemChrome="none" transparent="true" visible="true">[SWF reference is generated]</rootContent>
MacintoshとWindowsのFlexクローム
MacintoshとWindowsのFlexクローム

完全にオリジナルの外観にしたい場合は、MXMLのWindowedApplicationタグをApplicationタグに書き換えます。Applicationコンポーネントにはクロームがないため、背景だけの状態になります。さらに下記のようにスタイルを設定すれば背景も表示されなくなるので、自由な形状のパーツを配置してカスタムクロームを構成できます。ここではSWFLoaderコンポーネントを使って外部SWFファイルを読み込んでいます。

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Style>
		Application
		{
			background-image:"";
			background-color:"";
		}
	</mx:Style>
	<mx:SWFLoader x="0" y="0" source="clock.swf"/>
</mx:Application>
背景を透過させて自由な形のアプリケーションにできる
背景を透過させて自由な形のアプリケーションにできる

ウィンドウの最小化/最大化/クローズ

AIRアプリケーションのウィンドウはNativeWindowクラスのAPIでコントロールできます。各ウィンドウはNativeWindowクラスのインスタンスです。このオブジェクトにはStageクラスのwindowプロパティを使ってアクセスできます。下記はウィンドウのサイズ変更とクローズのサンプルです。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[
			private function onMinimizeButtonClick(evt:MouseEvent):void {
				stage.window.minimize();
			}
			private function onMaximizeButtonClick(evt:MouseEvent):void {
				stage.window.maximize();
			}
			private function onRestoreButtonClick(evt:MouseEvent):void {
				stage.window.restore();
			}
			private function onCloseButtonClick(evt:MouseEvent):void {
				stage.window.close();
			}
		]]>
	</mx:Script>
	<mx:Button x="10" y="10" label="最小化" click="onMinimizeButtonClick(event)"/>
	<mx:Button x="74" y="10" label="最大化" click="onMaximizeButtonClick(event)"/>
	<mx:Button x="140" y="10" label="元に戻す" click="onRestoreButtonClick(event)"/>
	<mx:Button x="214" y="10" label="閉じる" click="onCloseButtonClick(event)"/>
</mx:Application>

4つのボタンを配置し、clickイベントで各処理を行っています。minimize()メソッドはウィンドウを最小化し、maximize()メソッドは最大化します。変更前のサイズに戻すにはrestore()メソッドを使います。close()メソッドでウィンドウを閉じます。

ウィンドウの移動/リサイズ

システムクロームやFlexクロームを使っている場合には、特別な設定をしなくてもタイトルバーを掴んでウィンドウを移動したり、エッジを掴んでリサイズしたりできます。ですが、カスタムクロームでそういった動作を行うには、対応する処理を組み込む必要があります。下記はそのサンプルです。タイトルバーとリサイズボックスの代わりとして2つのHBoxコンポーネントを使っています。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[
			private function onTitleBarPress(evt:MouseEvent):void {
				stage.window.startMove();
			}
			private function onResizeBoxPress(evt:MouseEvent):void {
				stage.window.startResize(NativeWindowResize.BOTTOM_RIGHT);
			}
		]]>
	</mx:Script>
	<mx:HBox width="100%" height="20" backgroundColor="#666666" mouseDown="onTitleBarPress(event)"/>
	<mx:HBox width="20" height="20" backgroundColor="#666666" mouseDown="onResizeBoxPress(event)" right="0" bottom="0"/>
</mx:Application>

ウィンドウをドラッグして移動するには、mouseDownイベントをきっかけにstartMove()メソッドを呼び出します。するとマウスボタンを押している間はウィンドウをドラッグできます。マウスボタンを放すと自動的に移動停止します。停止用のメソッドはありません。

リサイズの場合も同様で、mouseDownイベントをきっかけにstartResize()メソッドを呼び出します。startResize()メソッドには、引数としてリサイズする方向を指定します。指定できる値はNativeWindowResizeクラスの定数として定義されています。サンプルではリサイズボックスを右下に配置しているので、NativeWindowResize.BOTTOM_RIGHTを指定しています。

NativeWindowResize.TOP
NativeWindowResize.BOTTOM
NativeWindowResize.LEFT
NativeWindowResize.RIGHT
NativeWindowResize.TOP_LEFT左上
NativeWindowResize.TOP_RIGHT右上
NativeWindowResize.BOTTOM_LEFT左下
NativeWindowResize.BOTTOM_RIGHT右下
NativeWindowResize.NONEリサイズしない

マウスドラッグによる操作以外に、NativeWindowクラスのプロパティを直接指定して位置やサイズを変更できます。位置を指定するにはx、yプロパティを、サイズを指定するにはwidth、heightプロパティを使います。

var appWin:NativeWindow = stage.window;
appWin.x = 100;
appWin.y = 100;
appWin.width = 640;
appWin.height = 480;

また、boundsプロパティを使えば位置とサイズを同時に指定できます。値はRectangle型です。

stage.window.bounds = new Rectangle(100, 100, 640, 480);

なお、カスタムクロームではウィンドウとステージのサイズが一致しますが、システムクロームの場合はウィンドウからクロームの領域を除いた範囲がステージになるので注意してください。

ウィンドウのサイズには上限と下限があり、それぞれmaxSize、minSizeプロパティに設定されています。値はPoint型です。この値を上書きしてリサイズ可能な範囲を設定できます。

var appWin:NativeWindow = stage.window;
appWin.minSize = new Point(320, 240);
appWin.maxSize = new Point(640, 480);

ウィンドウの状態を知る

現在のウィンドウの状態(通常/最小化/最大化)は、NativeWindowクラスのdisplayStateプロパティで調べることができます。各状態を表す値は、NativeWindowDisplayStateクラスの定数として定義されています。

NativeWindowDisplayState.MAXIMIZED最大化された状態
NativeWindowDisplayState.MINIMIZED最小化された状態
NativeWindowDisplayState.NORMAL通常の状態

次のステートメントはウィンドウが通常の状態であれば最大化し、そうでなければ元に戻します。

var appWin:NativeWindow = stage.window;
if (appWin.displayState == NativeWindowDisplayState.NORMAL) {
	appWin.maximize();
} else {
	appWin.restore();
}

ウィンドウの状態が変わる直前や変わった直後に処理を行いたい場合は、NativeWindowクラスのイベントを利用します。定義されているイベントには次の種類があります。

NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING最小化や最大化が行われる直前
NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGE最小化や最大化が行われた
NativeWindowBoundsEvent.MOVING移動される直前
NativeWindowBoundsEvent.MOVE移動された
NativeWindowBoundsEvent.RESIZINGリサイズされる直前
NativeWindowBoundsEvent.RESIZEリサイズされた
Event.ACTIVATEアクティブになった
Event.DEACTIVATE非アクティブになった
Event.CLOSING閉じられる直前
Event.CLOSE閉じられた

NativeWindowDisplayStateEventクラスにはbeforeDisplayStateとafterDisplayStateプロパティがあり、イベント受信時に変更前と変更後の状態を知ることができます。同様に、NativeWindowBoundsEventクラスには変更前と変更後の位置やサイズを知るためのbeforeBounds、afterBoundsプロパティがあります。下記はサイズ変更時や移動時のイベントを受け取るサンプルです。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">
	<mx:Script>
		<![CDATA[
			private function init():void {
				var appWin:NativeWindow = stage.window;
				appWin.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGE, onDisplayStateChange);
				appWin.addEventListener(NativeWindowBoundsEvent.MOVE, onBoundsChange);
				appWin.addEventListener(NativeWindowBoundsEvent.RESIZE, onBoundsChange);
			}
			private function onDisplayStateChange(evt:NativeWindowDisplayStateEvent):void {
				trace(evt.type, evt.beforeDisplayState, evt.afterDisplayState);
			}
			private function onBoundsChange(evt:NativeWindowBoundsEvent):void {
				trace(evt.type, evt.beforeBounds, evt.afterBounds);
			}
		]]>
	</mx:Script>
</mx:WindowedApplication>

NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGINGとEvent.CLOSINGについては、システムクロームまたはFlexクロームを使っている場合に配信されます。また、NativeWindowBoundsEvent.MOVINGとNativeWindowBoundsEvent.RESIZINGは、マウスドラッグによる操作の場合に配信されます。これらイベント名にINGのつくものは、その後に行われるデフォルト動作をキャンセルすることができます。下記のサンプルでは、ウィンドウが閉じられる直前にpreventDefault()メソッドでキャンセルしています。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">
	<mx:Script>
		<![CDATA[
			private function init():void {
				stage.window.addEventListener(Event.CLOSING, onClosing);
			}
			private function onClosing(evt:Event):void {
				evt.preventDefault();
				trace("クローズイベントをキャンセルしました");
			}
		]]>
	</mx:Script>
</mx:WindowedApplication>

新しいウィンドウを開く

NativeWindowクラス(またはそのサブクラス)のインスタンスを生成すれば、新しいウィンドウが開きます。下記のサンプルは、ユーティリティスタイルのウィンドウを開き、タイトルとサイズを設定しています。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[
			private function openWindow():void {
				var options:NativeWindowInitOptions = new NativeWindowInitOptions();
				options.type = NativeWindowType.UTILITY;
				var newWin:NativeWindow = new NativeWindow(false, options);
				newWin.title = "New Window";
				newWin.width = 160;
				newWin.height = 120;
				newWin.visible = true;
			}
		]]>
	</mx:Script>
	<mx:Button x="20" y="20" label="新規ウィンドウ" click="openWindow()"/>
</mx:WindowedApplication>

NativeWindowクラスのコンストラクタの最初の引数は、visibleプロパティの初期値です。ウィンドウの初期化処理を見せたくない場合などはfalseを指定しておき、後からtrueにできます。2番目の引数はNativeWindowInitOptionsクラスのインスタンスです。このオブジェクトはウィンドウの属性を決める様々なプロパティを保持しています。主なプロパティには次のものがあります。

systemChrome:Stringクロームの指定
transparent:Booleanアルファをサポートするかどうか
type:Stringウィンドウのタイプ
maximizable:Boolean最大化可能かどうか
minimizable:Boolean最小化可能かどうか
resizable:Booleanリサイズ可能かどうか

※Macintoshでリサイズを無効にするにはmaximizableとresizableの両方をfalseにする必要があります。

systemChromeプロパティはNativeWindowSystemChromeクラスの定数で指定します。

NativeWindowSystemChrome.STANDARDシステムクロームを使う
NativeWindowSystemChrome.NONEシステムクロームを使わない

typeプロパティはNativeWindowTypeクラスの定数で指定します。NORMAL以外のタイプはタスクバー等に表示されないウィンドウです。

NativeWindowType.NORMAL通常のウィンドウ
NativeWindowType.UTILITYユーティリティスタイルのウィンドウ
NativeWindowType.LIGHTWEIGHTクロームを持たないウィンドウ
MacintoshとWindowsのユーティリティスタイルのウィンドウ
MacintoshとWindowsのユーティリティスタイルのウィンドウ

いったん新規ウィンドウを開いたら、そのウィンドウが持つステージに対してSpriteオブジェクトなどを追加できます。ステージはNativeWindowクラスのstageプロパティで取得できます。次のステートメントは、新規に開いたウィンドウの中央に円を描画します。

var options:NativeWindowInitOptions = new NativeWindowInitOptions();
var newWin:NativeWindow = new NativeWindow(true, options);
var myStage:Stage = newWin.stage;
myStage.align = StageAlign.TOP_LEFT;
myStage.scaleMode = StageScaleMode.NO_SCALE;
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0xFFFF00);
circle.graphics.drawCircle(myStage.stageWidth / 2, myStage.stageHeight / 2, 40);
myStage.addChild(circle);

おすすめ記事

記事・ニュース一覧