akihiro kamijo: windowing API Archives

April 20, 2007

NativeWindow クラスのイベント(その2)

displayStateChanging イベントのキャンセル

前回書いたように、ing 系のイベントは必要に応じて処理自体をキャンセルするために使用できます。displayStateChanging イベントであれば displayState の変更をキャンセルするわけですから、最大化や最小化を行わないという指示を出すことになります。

AS3 では、イベントにより標準的に行われることになっている処理をキャンセルするには、イベントハンドラ内で preventDefault() を呼び出します。前回のサンプルをそのまま使うと、onDispStateEvent() メソッド内に preventDefault() を追加すればよいことになります。

onDispStateEvent() メソッドは displayStateChange と displayStateChanging イベントの両者で共用しているのでキャンセル不可のイベント (displayStateChange) も渡される可能性があります。そのため、キャンセル可能かを確認するロジックも追加しています。

private function onDispStateEvent(e:NativeWindowDisplayStateEvent):void {
  if (e.cancelable) {   // キャンセル可能かをチェック
    e.preventDefault(); // 標準処理をキャンセル
  }
  trace("type:", e.type, e.afterDisplayState);
}
 

実際にこのコードを実行してみると、システムクロームのボタンを押しても何も起こらないのに対して、アプリ内のボタンはそのまま有効なのが分かると思います。また、アプリ内のボタン押下時に明示的に displayStateChanging イベントのディスパッチを行うと、システムクロームのボタンと同様にキャンセル処理が有効になるのが確認できると思います。

NativeWindowBoundsEvent

NativeWindow の bounds 属性が変更されると NativeWindowBoundsEvent がディスパッチされます。bounds 属性が変更されるのはウインドウの位置か大きさが変わった場合です。

NativeWindowBoundsEvent は beforeBounds と afterBounds の属性を持っていて、それぞれ変更前の値と変更後の bounds 属性の値を示します。ing 系 (moving, resizing) のイベントでは beforeBounds がその時点での値、完了通知のイベント (move, resize) では afterBounds がその時点での値ということになります。

NativeWindowDisplayStateEvent のケースと同様に、move と resize イベントはそれぞれウインドウの位置もしくは大きさが変われば常にディスパッチされますが、moving と resizing はマウス操作で位置や大きさを変えた場合のみディスパッチされ、スクリプトから bounds 等の属性を変更した場合にはディスパッチされません。

これも NativeWindowDisplayStateEvent のケースと同様に、属性値の変更時に明示的に moving や resizing をディスパッチすることで、他のコンポーネントでもキャンセルを可能にすることができます。

ちなみに Stage クラスにも resize イベントがあります。こちらはステージの大きさが変更された後に描画開始できる状態になるとディスパッチされます。

以下は NativeWindowBoundsEvent の発生を確認するためのサンプルです。システムクロームを表示した状態で試してみてください。デバッグモードをお忘れなく。

<?xml version="1.0" encoding="utf-8"?>
<mx:ApolloApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="addListeners()">
  <mx:Script>
  <![CDATA[
    private function addListeners():void {
      stage.window.addEventListener(NativeWindowBoundsEvent.RESIZE, onBoundsEvent);
      stage.window.addEventListener(NativeWindowBoundsEvent.RESIZING, onBoundsEvent);
      stage.window.addEventListener(NativeWindowBoundsEvent.MOVE, onBoundsEvent);
      stage.window.addEventListener(NativeWindowBoundsEvent.MOVING, onBoundsEvent);
    }
    private function onBoundsEvent(e:NativeWindowBoundsEvent):void {
      trace("type:", e.type, e.afterBounds);
    }
    private function onBoxMouseDown(e:MouseEvent):void {
      stage.window.startResize(NativeWindowResize.BOTTOM_RIGHT);
    }
    private function onBarMouseDown(e:MouseEvent):void {
      stage.window.startMove( );
    }
  ]]>
  </mx:Script>
  <mx:HBox mouseDown="onBarMouseDown(event)" width="100%" height="24" backgroundColor="#ffffff"/>
  <mx:HBox mouseDown="onBoxMouseDown(event)" width="100%" height="100%" backgroundColor="#ffffff"/>
</mx:ApolloApplication>
 

close と closing イベント

最後に close と closing イベントです。これらのイベントは、ユーザがウインドウを閉じるボタンを押した時、閉じるまでに必要な処理があるケースなどに便利です。イベントの型は flash.events.Event です。

closing は閉じる直前に close は閉じた後に発生します。closing イベントをキャンセルすると、ウインドウを閉じるという処理自体をキャンセルできます。ただ closing イベントはシステムクロームの閉じるボタンを押した場合以外には自動的にディスパッチされないため、必要な場合には明示的にイベントを発生させる必要があります。この点は他の ing 系のイベントと同じです。

Posted by ackie at 05:16 PM | Comments (0)

April 19, 2007

NativeWindow クラスのイベント

以下は NativeWindow クラスのイベントのリストです。

displayStateChange    NativeWindow オブジェクトの displayState 属性が変更された
displayStateChanging  NativeWindow オブジェクトの displayState 属性が変更される直前
move                  NativeWindow オブジェクトがデスクトップ上で移動した
moving                NativeWindow オブジェクトがデスクトップ上で移動する直前
resize                NativeWindow オブジェクトの大きさが変更された
resizing              NativeWindow オブジェクトの大きさが変更される直前
close                 NativeWindow オブジェクトが閉じられた
closing               NativeWindow オブジェクトが閉じられる直前
  

ひとめで2つずつペアになっているのが分かるかと思います。4種類のウインドウに対する操作に対して、完了の直前と完了後それぞれの状態を通知するイベントが定義されています。

ing で終わるイベントは警告のような位置づけで、これを受け取ることで処理が完了する前に状況を確認したり、場合によっては処理自体をキャンセルするといった使い方が想定されています。そのため ing 系のイベントはいずれもキャンセル可能です。

一方 ing のつかないイベントは完了を通知するイベントです。事後処理が必要な場合に使用します。

では個々のイベントを少し詳しく見てみたいと思います。

NativeWindowDisplayStateEvent

まずは displayState 属性の変更に関連するイベントです。displayStateChanging は NativeWindow オブジェクトの displayState が変更される直前、displayStateChange は displayState が変更された後に該当する NativeWindow によってディスパッチされます。

このときディスパッチされるイベントオブジェクトの型は flash.events.NativeWindowDisplayStateEvent です。この型のイベントは beforeDisplayState と afterDisplayState の属性を持っていて、それぞれ変更前の値と変更後の値を示します。

displayStateChanging イベントの場合はまだ変更が完了していないので、イベントを受け取った時点での displayState 属性の値は beforeDisplayState の方ということになります。一方 displayStateChange イベントの場合は変更が既に行われているので、その時点の displayState 属性の値は afterDisplayState の方ということになります。

では早速サンプルコードを動かしてみましょう。まず、システムクロームを表示するようにアプリケーション記述ファイル内の rootContent タグの systemChrome が standard になっていることを確認します。

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

下のサンプルコードでは applicationComplete イベントのタイミングでイベントリスナ (onDispStateEvent) を追加しています。onDispStateEvent 内では trace() を使ってイベント情報を出力するようにしていますので、デバッグモードで実行してください。Flex Builder のコンソールにメッセージが出力されます。デバッグは虫のアイコンをクリックすると開始されます。

<?xml version="1.0" encoding="utf-8"?>
<mx:ApolloApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="addListeners()">
  <mx:Script>
  <![CDATA[
    private function addListeners():void {
      stage.window.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGE, onDispStateEvent);
      stage.window.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, onDispStateEvent);
    }
    private function onDispStateEvent(e:NativeWindowDisplayStateEvent):void {
      trace("type:", e.type, e.afterDisplayState);
    }
    private function onMinBtnClick(e:MouseEvent):void
    {
      stage.window.minimize();
    }
    private function onMaxBtnClick(e:MouseEvent):void
    {
      if (stage.window.displayState != NativeWindowDisplayState.MAXIMIZED)
      {
        stage.window.maximize();
        maxBtn.label = "v";
      }
      else
      {
        stage.window.restore();
        maxBtn.label = "\u25A2";
      }
    }
    private function onCloseBtnClick(e:MouseEvent):void
    {
      stage.window.close();
    }
  ]]>
  </mx:Script>
  <mx:HBox width="100%" backgroundColor="#ffffff">
    <mx:Button id="minBtn" label="_" click="onMinBtnClick(event)" />
    <mx:Button id="maxBtn" label='{"\u25A2"}' click="onMaxBtnClick(event)" />
    <mx:Button id="closeBtn" label="X" click="onCloseBtnClick(event)" />
  </mx:HBox>
  <mx:HBox width="100%" height="100%" backgroundColor="#ffffff"/>
</mx:ApolloApplication>
 

注意深くテストをした人は、システムクロームの最小化 / 最大化ボタンと、ウインドウ内の最小化 / 最大化ボタンとで押された後のイベントに違いがあるのに気づいたことと思います。

システムクロームのボタンからウインドウを最大化したり元に戻したりすると displayStateChanging と displayStateChange の両方のイベントが発生します。

一方、ウインドウ内のボタンを押した場合は displayStateChange イベントしか発生しません。(つまり ing イベントは発生しません)

これは、システムクロームから操作がされた場合、その操作によりリクエストされた処理が実際に行われる前に対応することが可能なようにという配慮によるものです。そのため、NativeWindow が displayStateChanging を自動的にディスパッチするのです。

一方、ウインドウ内のボタンから minimize() 等のメソッドを呼び出す場合は、呼び出す前に必要な対応を記述しておくことが可能なはずです。そのため minimize(), maximize(), restore() を呼んでも displayStateChanging は自動的にはディスパッチされません。

もし minimize() 等による displayState の変更に対しても displayStateChanging イベントが必要な場合には、以下のような記述を追加します。下は minimize() が呼ばれた場合です。

private function onMinBtnClick(e:MouseEvent):void
{
  stage.window.minimize();
  var dispStateEvent:NativeWindowDisplayStateEvent = 
    new NativeWindowDisplayStateEvent(
      NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, true, true, 
      stage.window.displayState, NativeWindowDisplayState.MINIMIZED);
    stage.window.dispatchEvent(dispStateEvent);
}
 

ApolloApplicaton のクロームではこれと同様な処理が追加されています。アプリケーション記述ファイルの rootContent タグの systemChrome を none にして ApolloApplication のクロームを表示すると displayStateChanging を確認することができます。

ちょっと長くなってしまいましたのでイベント話の続きはまた次回。

Posted by ackie at 05:48 PM | Comments (0)

April 18, 2007

新しい Apollo ウインドウを開く方法

Apollo アプリケーションから新しいウインドウを開くには NativeWindow もしくはそのサブクラスのインスタンスを生成します。下は NativeWindow のコンストラクタです。

public function NativeWindow(visible:Boolean, initOptions:NativeWindowInitOptions)
 

NativeWindow のコンストラクタは2つの引数を取ります。

1 つ目の引数はウインドウが作成されたときに表示するかしないかのフラグです。ウインドウを作成したら表示位置や大きさなどに多少の細工を加えることも多いと思います。ウインドウが表示された状態でこれらの処理を行うと途中の段階も画面に表示されてしまいますので、とりあえずコンストラクタでは false (非表示) を指定しておいて、必要な処理が終わったら window.visible = true を呼んでウインドウを表示するというのが一般的にはよさそうですね。

同様に、アプリケーション起動時に画面に表示したくない初期処理が存在する場合は、アプリケーション記述ファイル (-app.xml) 内 rootContent タグの visible を false にしておいて適当なタイミングで window.visible = true を呼ぶことで対応できます。

2 つ目の引数はウインドウの初期化に使われるオプションを指定する NativeWindowInitOptions 型のオブジェクトです。以下のような項目が NativeWindowInitOptions クラスに定義されています。

systemChrome:String  // ウインドウが使用するシステムクロームの種類
transparent:Boolean  // ウインドウが透けた背景を使用できるか
resizable:Boolean    // ウインドウの大きさを変更できるか
maximizable:Boolean  // ウインドウを最大化できるか
minimizable:Boolean  // ウインドウを最小化できるか
 

それぞれの属性の初期値は以下のようになっています。変更の必要があるものだけ指定すれば OK です。

systemChrome = NativeWindowSystemChrome.STANDARD;
transparent = false;
resizable = true;
maximizable = true;
minimizable = true;
 

systemChrome の取り得る値は NativeWindowSystemChrome クラスに定義されています。現在のアルファ版で使用できるのは以下の 2 種類だけです。

public static const STANDARD:String // OS 標準のクロームを使用
public static const NONE:String     // OS のクロームを使用しない
 

NativeWindowSystemChrome.NONE を指定した場合はクローム無し、つまり枠の内側のみのウインドウが表示されます。

ここまでまとめに、新しいウインドウを開くときの基本的な関数のサンプルです。

public function createNewWindow():void {
  // ウインドウ初期化オプションを作成
  var options:NativeWindowInitOptions = new NativeWindowInitOptions();
  // ここで必要に応じてオプションを設定
 
  // ウインドウの作成
  var newWindow:NativeWindow = new NativeWindow(false,options);
 
  // ここに必要な処理を記述
 
  // ウインドウを可視化
  newWindow.visible = true;
}	
 

owner 属性

NativeWindowInitOptions クラスには owner という属性があります。この属性には新しく作成するウインドウのオーナーとなるウインドウを指定することができます。

owner を指定してウインドウを初期化すると、作成されたウインドウは常に自身の owner の上に表示されるようになります。owner ウインドウがフォーカスされてもお互いの重なり順は変わりません。

また、owner ウインドウが閉じられるとそのウインドウを owner に持つ全てのウインドウが閉じられます。

下のサンプルでは最初のアプリケーションウインドウがアプリーケーション起動後に開いたウインドウの owner になっています。そのため、アプリケーションウインドウを閉じるといくつウインドウが開いていても全てのウインドウが閉じられ、アプリケーションが終了します。

<?xml version="1.0" encoding="utf-8"?>
<mx:ApolloApplication xmlns:mx="http://www.adobe.com/2006/mxml" width="350" height="200">
  <mx:Script>
  <![CDATA[
  public function createNewWindow():void {
    // ウインドウ初期化オプションを作成
    var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    options.owner = stage.window;
 
    // ウインドウの作成
    var newWindow:NativeWindow = new NativeWindow(false,options);
    newWindow.width = 400;
    newWindow.height = 300;
 
    // ウインドウにテキストフィールドを追加
    newWindow.stage.align = StageAlign.TOP_LEFT;
    newWindow.stage.scaleMode = StageScaleMode.NO_SCALE;
    var tf:TextField = new TextField();
    tf.width = newWindow.width;
    tf.text = "これは空のウインドウです";
    newWindow.stage.addChild(tf);
 
    // ウインドウを可視化
    newWindow.visible = true;
  }
  ]]>
  </mx:Script>
  <mx:Button label="ウインドウを開く" click="createNewWindow();"/>
</mx:ApolloApplication>
 

なお、アルファ版の制限として Flex のコンポーネントが追加できません。このサンプルではテキストフィールドを使用しています。

Posted by ackie at 05:00 PM | Comments (0)

April 12, 2007

Apollo ウインドウの位置とサイズを変える色々な属性

NativeWindow クラスには Apollo アプリケーションのウインドウの位置や大きさを示すプロパティがあります。

x:Number       // ウインドウの左上の角の x 座標
y:Number       // ウインドウの左上の角の y 座標
width:Number   // ウインドウの幅(単位:ピクセル)
height:Number  // ウインドウの高さ(単位:ピクセル)
 

これらのプロパティに値を設定することでウインドウの位置や大きさを変えることができます。

stage.window.x = 50;
stage.window.y = 50;
stage.window.width = 800;
stage.window.height = 600;
 

ウインドウの幅と高さに指定できる最小値と最大値は予め決められています。最小値より小さな値を指定すると最小値として与えられている大きさになります。つまり下限の定義よりウインドウを小さくすることはできません。同様に最大値として定義されている値よりウインドウを大きくすることもできません。

最大値と最小値はそれぞれ以下のプロパティから参照できます。当然ですがこれらのプロパティは読み取り専用です。

maxSize:Point  // ウインドウの大きさの最大値
minSize:Point  // ウインドウの大きさの最小値
 

どちらも Point 型 (Class Point@livedocs) で、座標値として大きさの上限または下限を指定します。例えば、maxSize.x はウインドウ幅の上限、maxSize.y はウインドウ高さの上限です。

ちなみに、maximize() を呼んだ後のウインドウの大きさは maxSize に定義されている上限の値と同じになります。

それから、プロパティを使ってウインドウを最大化した場合 reset() を呼んでも元には戻りません。displayState が NORMAL のままのためです。

bounds 属性

NativeWindow の bounds 属性を使うと位置と大きさをいっぺんに指定することができます。

bounds:Rectangle  // ウインドウの位置と大きさ
 

Rectangle 型 (Class Rectangle@livedocs) のオブジェクトで座標情報を管理するわけです。例えば上の例は以下のように書き直すことができます。

// ウインドウ左上角の座標を (50, 50) 幅を 800 高さを 600 に設定
stage.window.bounds = new Rectangle(50, 50, 800, 600);
 

NativeWindow と Stage

ところで、ウインドウの大きさはシステムクロームが使用されていた場合にはクロームの大きさも含みます。ウインドウ内のクローム以外の領域がステージ (window.stage) です。

ステージ領域の大きさは stage オブジェクトの属性から取得することができます。Stage クラスには stageWidth と stageHeight という属性がありそれぞれ stage オブジェクトの幅と高さを表しています。

これらの属性に値を代入すると stage の大きさが変わります。そのためステージを表示しているウインドウの大きさも変わります。

stage.stageWidth = 800;
stage.stageHeight = 600;
 

stage と window が同じ display list に属していることになるので stage と stage.window.stage は 同じオブジェクトのはずですね。

Posted by ackie at 06:37 PM | Comments (0)

April 10, 2007

Apollo ウインドウの移動とリサイズの実現

ふつうのウインドウだったらマウスでウインドウの位置を変えたり大きさを変えたりできますよね?今回はそれらの機能を追加したいと思います。

startMove() メソッド

startMove() は NativeWindow クラスのメソッドです。

public function startMove():void
 

マウスのボタンを押すと mouseDown イベントが発生します。この状態で startMove() メソッドを呼び出すと、マウスボタンを離す (もしくは何らかのマウスイベントが発生する) までマウスの動きに従ってウインドウを移動させることができます。

移動終了の判断は Apollo 側で勝手に行いますので、特に設定する必要はありません。ですので stopMove() といった類のメソッドは提供されていません。

ちなみに Windows では mouseDown 以外のタイミングから startMove() を呼ぶとキー操作による移動も可能になるようです。

さて、前回のサンプルにタイトルバーを使った移動ができるように機能を追加してみましょう。

まずはタイトルバーのコンポーネントがマウス操作に反応するよう mouseDown イベントに対するイベントハンドラを指定します。

<mx:HBox mouseDown="onTitleBarMouseDown(event)" styleName="box" width="100%">
 

イベントハンドラの側で必要な処理は startMove() を呼び出すことだけです。

private function onTitleBarMouseDown(e:MouseEvent):void {
  stage.window.startMove( );
}
 

これで、タイトルバーを掴んで動かすことができるようになりました。

startResize() メソッド

次にウインドウのリサイズ処理を開始する startResize() メソッドの使い方です。

public function startResize(edgeOrCorner:String):void
 

このメソッドも、上で説明した startMove() と同様に、mouseDown のイベントハンドラ内で呼ばれると mouseUp イベントが発生するまで処理 (こっちの場合はマウスの動きに従ってウインドウの大きさを変更) を続けます。リサイズ終了の処理の記述が必要ない点も startMove() と似ています。

startResize() メソッドの引数にはリサイズを行う方向 (下向きとか左向きとか) を指定します。ということは、マウスの押された場所によって、指定する引数を変更するロジックが必要になるということです。例えば、押された場所が右下の角であれば、右側と下側両方の辺をリサイズの対象とするように引数を指定する必要があります。(普通のアプリの場合)

このとき引数として指定できるオプションには以下のものがあります。NativeWindowResize クラスに定義されています。

NativeWindowResize.TOP          // 上方向にリサイズ
NativeWindowResize.BOTTOM       // 下方向にリサイズ
NativeWindowResize.LEFT         // 左方向にリサイズ
NativeWindowResize.RIGHT        // 右方向にリサイズ
NativeWindowResize.TOP_LEFT     // 上と左方向にリサイズ
NativeWindowResize.TOP_RIGHT    // 上と右方向にリサイズ
NativeWindowResize.BOTTOM_LEFT  // 下と左方向にリサイズ
NativeWindowResize.BOTTOM_RIGHT // 下と右方向にリサイズ
NativeWindowResize.NONE         // どの方向にもリサイズしない
 

下のサンプルコードは右下方向にリサイズする処理を開始するものです。分かりやすくするために反応する領域を大きめに取っています。

private function onBoxMouseDown(e:MouseEvent):void {
  // 反応する領域の大きさ
  var dragArea:int = 300;
  // マウスが右下の角にあるかチェック
  if ((mouseY > (height - dragArea)) && (mouseX > (width - dragArea))) {
    stage.window.startResize(NativeWindowResize.BOTTOM_RIGHT);
  }
}
 

このメソッドを呼び出す記述を追加すると前回のサンプルでもリサイズができるようになります。下が修正したコードです。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
  <![CDATA[
    private function onMinBtnClick(e:MouseEvent):void
    {
      stage.window.minimize( );
    }
    private function onMaxBtnClick(e:MouseEvent):void
    {
      if (stage.window.displayState != NativeWindowDisplayState.MAXIMIZED)
      {
        stage.window.maximize( );
        maxBtn.label = "v";
      }
      else
      {
        stage.window.restore( );
        maxBtn.label = "\u25A2";
      }
    }
    private function onCloseBtnClick(e:MouseEvent):void
    {
      stage.window.close( );
    }
    private function onTitleBarMouseDown(e:MouseEvent):void {
      stage.window.startMove( );
    }
    private function onBoxMouseDown(e:MouseEvent):void {
      var dragArea:int = 300;
      if ((mouseY > (height - dragArea)) && (mouseX > (width - dragArea))) {
        stage.window.startResize(NativeWindowResize.BOTTOM_RIGHT);
      }
    }
  ]]>
  </mx:Script>
  <mx:Style>
    Application
    {
      background-color:"";
      background-image:"";
    }
    .box {
      backgroundColor:#888888;
      backgroundAlpha:0.8;
    }
  </mx:Style>
  <mx:HBox mouseDown="onTitleBarMouseDown(event)" styleName="box" width="100%">
    <mx:Button id="minBtn" label="_" click="onMinBtnClick(event)" />
    <mx:Button id="maxBtn" label='{"\u25A2"}' click="onMaxBtnClick(event)" />
    <mx:Button id="closeBtn" label="X" click="onCloseBtnClick(event)" />
  </mx:HBox>
  <mx:HBox mouseDown="onBoxMouseDown(event)" styleName="box" width="100%" height="100%"/>
</mx:Application>
 

Posted by ackie at 06:47 PM | Comments (0)

April 09, 2007

NativeWindowDisplayState クラス

NativeWindowDisplayState クラス

ウインドウの現在の表示状態を知りたいとき、NativeWindow クラスの displayState プロパティ (読み取り専用) から取得することができます。

var windowStatus:String = stage.window.displayState;
 

このプロパティの持つ値は NativeWindowDisplayState というクラスに定義されています。とりうる値は以下の3種類です。

NativeWindowDisplayState.NORMAL     // ウインドウは通常の表示状態である
NativeWindowDisplayState.MINIMIZED  // ウインドウは最小化されている
NativeWindowDisplayState.MAXIMIZED  // ウインドウは最大化されている
 

これを使うと前回紹介した NativeWindow のメソッドは以下のように理解することができます。

public function maximize():void // displayState を MAXIMIZED にする
public function minimize():void // displayState を MINIMIZED にする
public function restore():void  // displayState を NORMAL にする
 

ウインドウの displayState を変更できるのはこの3つのメソッドのみです。(いまのところ)

さて、以上を踏まえて前回のサンプルを修正してみます。

前回のサンプルでは4つのボタン(最小 / 最大 / 戻る / 閉じる)が常に表示されたままでした。

maximize() メソッドはウインドウが最大化されていれば呼ばれても何もしません。つまり悪さはしません。 (minimize() メソッドも同様です) ですが、押しても何もしないボタンが表示されているのもなんですので、一般的な OS のウインドウのように1つのボタンで”最大化”と”戻る”の操作を兼ねるようにしたいと思います。

アプリケーションの起動時はウインドウは最大化されていないと考えてよいと思われるので、最初は最大化ボタンを表示しておき、その後はボタンが押されるたびにウインドウの状態により動作を切り替えるという方針をとることにします。

そうすると最大化ボタンが押されたときに呼び出される onMaxBtnClick() は以下のように書き直すことができます。

private function onMaxBtnClick(e:MouseEvent):void
{
  if (stage.window.displayState != NativeWindowDisplayState.MAXIMIZED)
  {
    stage.window.maximize( );
    maxBtn.label = "v";
  }
  else
  {
    stage.window.restore( );
    maxBtn.label = "\u25A2";
  }
}
 

上のメソッド内では、最初に displayState の値を調べたらその値に従って呼び出すメソッドとボタンのラベルを変更しています。

大きさを戻す専用のボタンはいらなくなるため全体のコードは以下のようになります。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
  <![CDATA[
    private function onMinBtnClick(e:MouseEvent):void
    {
      stage.window.minimize( );
    }
    private function onMaxBtnClick(e:MouseEvent):void
    {
      if (stage.window.displayState != NativeWindowDisplayState.MAXIMIZED)
      {
        stage.window.maximize( );
        maxBtn.label = "v";
      }
      else
      {
        stage.window.restore( );
        maxBtn.label = "\u25A2";
      }
    }
    private function onCloseBtnClick(e:MouseEvent):void
    {
      stage.window.close( );
    }
  ]]>
  </mx:Script>
  <mx:Style>
    Application
    {
      background-color:"";
      background-image:"";
    }
    .box {
      backgroundColor:#888888;
      backgroundAlpha:0.8;
    }
  </mx:Style>
  <mx:HBox styleName="box" width="100%">
    <mx:Button id="minBtn" label="_" click="onMinBtnClick(event)" />
    <mx:Button id="maxBtn" label='{"\u25A2"}' click="onMaxBtnClick(event)" />
    <mx:Button id="closeBtn" label="X" click="onCloseBtnClick(event)" />
  </mx:HBox>
  <mx:HBox styleName="box" width="100%" height="100%"/>
</mx:Application>
 

Posted by ackie at 06:37 PM | Comments (0)

April 06, 2007

Apollo ウインドウに最大/最小化と閉じるボタンを追加

Apollo アプリケーションのウインドウは NativeWindow というクラスのインスタンスです。この NativeWindow クラスの API を使うとウインドウを閉じたり最大化したりできます。

NativeWindow クラス

DisplayObject のインスタンス (画面に表示されるオブジェクトは基本的にみんなそうです) であれば、自身が所属する表示領域を stage 属性に持っています。この stage 属性から stage を表示している NativeWindow オブジェクトを取得することができます。

// DisplayObject のインスタンス内では以下の記述が可能
var window:NativeWindow = stage.window;
 

Stage の window プロパティは Apollo 実行環境でのみ有効で、Flash Player 環境では存在しません。プラグインは個別のウインドウを持たないので当たり前といえば当たり前ですが。

ちなみに、アプリケーションから実行環境を調べる方法の一つとして System.Capabilities.playerType が使えます。

public function isDesktopPlayer():Boolean
{
  return (Capabilities.playerType == "Desktop");
}
 

さて、NativeWindow クラスにはウインドウの大きさを操作するためのメソッドがいくつか提供されています。

public function maximize():void // ウインドウを最大化する
public function minimize():void // ウインドウを最小化する
public function restore():void  // ウインドウの大きさを元に戻す
public function close():void    // ウインドウを閉じる
 

maximize() と minimize() はそれぞれウインドウを最小化 / 最大化するメソッドです。restore() はウインドウが最小化または最大化された状態からそれ以前の位置と大きさにウインドウを復元するメソッドです。

4つ目の close() はウインドウを閉じるメソッドです。一度閉じたウインドウを再度開くことはできません。一時的ににウインドウを隠すだけであれば visible 属性を使う方法があります。

displayObject.stage.window.visible = false; // ウインドウを一時的に隠す
 

後で visible 属性を true に設定すれば再びウインドウが表示されます。(ちなみにアプリケーション記述ファイル (アプリ名-app.xml) の rootContent タグの3つめの属性の visible で設定されるのもこの属性です)

以下はこれらのメソッドを使ったサンプルです。Application のスタイル指定でメインウインドウの背景を透明にしているため、2つの HBox に明示的に背景色を指定しています。 (注:app.xml 内 rootContent タグの属性値変更をお忘れなく)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
  <![CDATA[
    private function onMinBtnClick(e:MouseEvent):void
    {
      stage.window.minimize( );
    }
    private function onMaxBtnClick(e:MouseEvent):void
    {
      stage.window.maximize( );
    }
    private function onRestoreBtnClick(e:MouseEvent):void
    {
      stage.window.restore( );
    }
    private function onCloseBtnClick(e:MouseEvent):void
    {
      stage.window.close( );
    }
  ]]>
  </mx:Script>
  <mx:Style>
    Application
    {
      background-color:"";
      background-image:"";
    }
    .box {
      backgroundColor:#888888;
      backgroundAlpha:0.8;
    }
  </mx:Style>
  <mx:HBox styleName="box" width="100%">
    <mx:Button id="minBtn" label="_" click="onMinBtnClick(event)" />
    <mx:Button id="maxBtn" label='{"\u25A2"}' click="onMaxBtnClick(event)" />
    <mx:Button id="restoreBtn" label='{"v"}' click="onRestoreBtnClick(event)" />
    <mx:Button id="closeBtn" label="X" click="onCloseBtnClick(event)" />
  </mx:HBox>
  <mx:HBox styleName="box" width="100%" height="100%"/>
</mx:Application>
 

今回紹介した4つのメソッドの実行は非同期です。完了通知はイベントによって行われます。

Posted by ackie at 06:15 PM | Comments (0)