# 37.6. `FrameWork` --- 対話型アプリケーション・フレームワーク

`FrameWork` モジュールは、対話型 Macintosh アプリケーションのクラスで、同時にフレームワークを提供します。プログラマは、サブクラスを作って基底クラスの様々なメソッドをオーバーライドし、必要な機能を実装することでアプリケーションを組み立てられます。機能のオーバーライドは、時によって様々な異なるレベルで行われます。つまり、ある一つのダイアログウィンドウでクリックの処理を普段と違う方法で行うには、完全なイベント処理をオーバーライドする必要はありません。

注釈

このモジュールは Python 3.x で削除されました。

`FrameWork` の開発は事実上停止しています。現在では `PyObjC` を使用すれば Python から Cocoa の全機能を使用することができます。このドキュメントでは最も重要な機能だけしか記述していませんし、それさえも論理的な形で書かれてもいません。ソースか例題を詳しく見てください。次にあげるのは、MacPython ニュースグループにポストされたコメントで、 `FrameWork` の強力さと限界について述べています。

> `FrameWork` の最大の強みは、制御の流れをたくさんの異なる部分に分割できることです。例えば `W` を使って、いろいろな方法でメニューをオン/オフしたり、残りをいじらずにうまくプラグインさせることができます。 `FrameWork` の弱点は、コマンドインタフェースが抽象化されていないこと (といっても難しいわけではないですが)、ダイアログサポートが最低限しかないこと、それからコントロール/ツールバーサポートが全くないことです。

`FrameWork` モジュールは以下の関数を定義しています:

`FrameWork.``Application`()

  アプリケーション全体を表現しているオブジェクト。メソッドについての詳細は以下の記述を参照してください。デフォルト `__init__()` ルーチンは、空のウィンドウ辞書とアップルメニューつきのメニューバーを作成します。

`FrameWork.``MenuBar`()

  メニューバーを表現するオブジェクト。このオブジェクトは普通はユーザは作成しません。

`FrameWork.``Menu`(bar, title[, after])

  メニューを表現するオブジェクト。生成時には、メニューが現われる `MenuBar` と、 title 文字列、メニューが表示されるべき (1 から始まる) 位置 after (デフォルトは末尾) を渡します。

`FrameWork.``MenuItem`(menu, title[, shortcut, callback])

  メニューアイテムオブジェクトを作成します。引数は作成するメニューと、アイテムのタイトル文字列、オプションのキーボードショートカット、コールバックルーチンです。コールバックは、メニュー ID、メニュー内のアイテム番号 (1 から数える)、現在のフロントウィンドウ、イベントレコードを引数に呼ばれます。

  呼び出し可能なオブジェクトのかわりに、コールバックは文字列でも良いです。この場合、メニューの選択は、最前面のウィンドウとアプリケーションの中でメソッド探索を引き起こします。メソッド名は、コールバック文字列の前に `'domenu_'` を付けたものです。

  `MenuBar` の `fixmenudimstate()` メソッドを呼びだすと、現在のフロントウィンドウにもとづいて、適切なディム化を全てのメニューアイテムに対して施します。

`FrameWork.``Separator`(menu)

  メニューの最後にセパレータを追加します。

`FrameWork.``SubMenu`(menu, label)

  label の名前のサブメニューを、メニュー menu の下に作成します。メニューオブジェクトが返されます。

`FrameWork.``Window`(parent)

  (モードレス) ウィンドウを作成します。 Parent は、ウィンドウが属するアプリケーションオブジェクトです。作成されたウィンドウはまだ表示されません。

`FrameWork.``DialogWindow`(parent)

  モードレスダイアログウィンドウを作成します。

`FrameWork.``windowbounds`(width, height)

  与えた幅と高さのウィンドウを作成するのに必要な、 `(left, top, right, bottom)` からなるタプルを返します。ウィンドウは以前のウィンドウに対して位置をずらして作成され、全体のウィンドウが画面からなるべく外れないようにします。しかし、ウィンドウはいつでも与えたのと全く同じサイズで、そのため一部は画面から隠れる場合もあります。

`FrameWork.``setwatchcursor`()

  マウスカーソルを時計型に設定します。

`FrameWork.``setarrowcursor`()

  マウスカーソルを矢印型に設定します。

## 37.6.1. Application オブジェクト

Application オブジェクトのメソッドは各種ありますが、次のメソッドをあげておきます。

`Application.``makeusermenus`()

  アプリケーションでメニューを使う必要がある場合、このメソッドをオーバーライドします。属性 `menubar` にメニューを追加します。

`Application.``getabouttext`()

  このメソッドをオーバーライドすることで、アプリケーションの説明を記述するテキスト文字列を返します。代わりに、 `do_about()` メソッドをオーバーライドすれば、もっと凝った "about" (…について) メッセージを出す事ができます。

`Application.``mainloop`([mask[, wait]])

  このルーチンがメインイベントループで、作成したアプリケーションが動き出すためにはこれを呼ぶことになります。 Mask は操作したいイベントを選択するマスクです。 wait は並行に動作しているアプリケーションに割り当てたいティック数 (1/60 秒) です (デフォルトで 0 ですが、あまり良い値ではありません)。 self フラグを立ててメインループを抜ける方法はまだサポートされていますが、これはお勧めできません。代わりに `self._quit()` を呼んでください。

  イベントループは小さなパーツに分割されていて、各々をオーバーライドできるようになっています。これらのメソッドは、デフォルトでウィンドウとダイアログや、ドラッグとリサイズの操作、 AppleEvent、非 FrameWork のウィンドウに関するウィンドウの操作などに関するイベントをディスパッチすることなどまで面倒をみてくれます。

  原則として、全てのイベントハンドラは、イベントが完全に取り扱われた場合は `1` を返さなくてはいけませんし、それ以外では `0` を返さなくてはいけません (例えば、前面のウィンドウは FrameWork ウィンドウではない場合を考えてください)。こうしなくてはいけない理由は、アップデートイベントなどが Sioux コンソールウィンドウなどの他のウィンドウにきちんと渡されるようにするためです。 our_dispatch やその呼び出し元の内部から `MacOS.HandleEvent()` を呼んではいけません。そうしたコードが Python の内部ループのイベントハンドラを経由して呼ばれると、無限ループになりかねないからです。

`Application.``asyncevents`(onoff)

  非同期でイベント操作をしたい場合は、非ゼロの引数でこのメソッドを呼んでください。こうすることで、イベントが生じた時に、内部のインタプリタのループで、アプリケーションイベントハンドラ async_dispatch が呼ばれることになります。すると、長時間の計算を行っている場合でも、FrameWork ウィンドウがアップデートされ、ユーザーインターフェースが動き続けるようになります。ただし、インタプリタの動作が減速し、非リエントラントのコード (例えば FrameWork 自身など) に奇妙な動作が見られるかもしれません。デフォルトでは async_dispatch はすぐに our_dispatch を呼びますが、このメソッドをオーバーライドすると、特定のイベントを非同期で操作しても良くなります。処理しないイベントは Sioux などに渡されることになります。

  戻り値は以前の on あるいは off 値です。

`Application.``_quit`()

  実行中の `mainloop()` 呼び出しを、次の適当なタイミングで終了させます。

`Application.``do_char`(c, event)

  ユーザーが文字 c をタイプした時に呼ばれます。イベントの全詳細は event 構造体の中にあります。このメソッドは "Window" オブジェクト内で使うためにも提供されています。このオブジェクトのウィンドウが最前面にある場合にアプリケーション全体としてのハンドラとして使われます。

`Application.``do_dialogevent`(event)

  イベントループ内部で最初のほうで呼ばれて、モードレスダイアログイベントを処理します。デフォルトではメソッドは単にイベントを適切なダイアログにディスパッチするだけです (関連した `DialogWindow` オブジェクトを経由してではありません)。特別にダイアログイベント (キーボードショートカットなど) を処理する必要がある場合にオーバーライドしてください。

`Application.``idle`(event)

  イベントが無い場合にメインイベントループから呼ばれます。 null イベントも渡されます (つまりマウス位置などを監視することができます)。

## 37.6.2. Window オブジェクト

Window オブジェクトは特に次のメソッドを持ちます:

`Window.``open`()

  ウィンドウを開く時はこのメソッドをオーバーライドします。Mac OS ウィンドウ ID を `self.wid` に入れて `do_postopen()` メソッドを呼ぶと、親アプリケーションにウィンドウを登録します。

`Window.``close`()

  ウィンドウを閉じるときに特別な処理をする場合はこのメソッドをオーバーライドします。親アプリケーション状態をクリーンアップするには、 `do_postclose()` を呼びます。

`Window.``do_postresize`(width, height, macoswindowid)

  ウィンドウがリサイズされた後に呼ばれます。 `InvalRect` を呼び出す以外にもすることがある場合はこれをオーバーライドします。

`Window.``do_contentclick`(local, modifiers, event)

  ウィンドウのコンテント部分をユーザーがクリックすると呼ばれます。引数は位置座標 (ウィンドウを基準)、キーモディファイア、生のイベントです。

`Window.``do_update`(macoswindowid, event)

  ウィンドウの更新イベントが受信された時に呼ばれます。ウィンドウを再描画します。

`Window.``do_activate`(activate, event)

  ウィンドウがアクティブ化( `activate == 1`)、非アクティブ化 (`activate == 0`) する際に呼ばれます。フォーカスのハイライトなどを処理します。

## 37.6.3. ControlsWindow オブジェクト

ControlsWindow オブジェクトには `Window` オブジェクトのメソッドの他に次のメソッドがあります:

`ControlsWindow.``do_controlhit`(window, control, pcode, event)

  コントロール control のパートコード pcode がユーザにヒットされた場合に呼ばれます。トラッキングなどは任せておいてかまいません。

## 37.6.4. ScrolledWindow オブジェクト

ScrolledWindow オブジェクトは、次のメソッドを追加した ControlsWindow オブジェクトです。

`ScrolledWindow.``scrollbars`([wantx[, wanty]])

  水平スクロールバーと垂直スクロールバーを作成します (あるいは破棄します)。引数はどちらが欲しいか指定します (デフォルトは両方)。スクロールバーは常に最小値 `0` 、最大値 `32767` です。

`ScrolledWindow.``getscrollbarvalues`()

  このメソッドは必ず作っておかなくてはいけません。現在のスクロールバーの位置を与えるタプル `(x, y)` を (`0` の `32767` 間で) 返してください。バーの方向について文書全体が可視状態であること知らせるため `None` を返す事もできます。

`ScrolledWindow.``updatescrollbars`()

  文書に変更があった場合はこのメソッドを呼びます。このメソッドは `getscrollbarvalues()` を呼んでスクロールバーを更新します。

`ScrolledWindow.``scrollbar_callback`(which, what, value)

  あらかじめ与えておくメソッドで、ユーザーとの対話により呼ばれます。 which は `'x'` か `'y'` 、 what は `'-'`, `'--'`, `'set'`, `'++'`, `'+'` のどれかです。 `'set'` の場合は、 value に新しいスクロールバー位置を入れておきます。

`ScrolledWindow.``scalebarvalues`(absmin, absmax, curmin, curmax)

  `getscrollbarvalues()` の結果から値を計算するのを助ける補助的なメソッドです。文書の最小値と最大値、可視部分に関する上端値 (左端値) と下端値 (右端値) を渡すと、正しい数か `None` を返します。

`ScrolledWindow.``do_activate`(onoff, event)

  ウィンドウが最前面になった時、スクロールバーのディム (dimming)/ハイライトの面倒をみます。このメソッドをオーバーライドするなら、オーバーライドしたメソッドの最後でオリジナルのメソッドを呼んでください。

`ScrolledWindow.``do_postresize`(width, height, window)

  スクロールバーを正しい位置に移動させます。オーバーライドする時は、オーバーライドしたメソッドの一番最初でオリジナルのメソッドを呼んでください。

`ScrolledWindow.``do_controlhit`(window, control, pcode, event)

  スクロールバーのインタラクションを処理します。これをオーバーライドする時は、オリジナルのメソッドを最初に呼び出してください。非ゼロの返り値はスクロールバー内がヒットされたことを意味し、実際に処理が進むことになります。

## 37.6.5. DialogWindow オブジェクト

DialogWindow オブジェクトには、 `Window` オブジェクトのメソッドの他に次のメソッドがあります:

`DialogWindow.``open`(resid)

  ID resid の DLOG リソースからダイアログウィンドウを作成します。ダイアログオブジェクトは `self.wid` に保存されます。

`DialogWindow.``do_itemhit`(item, event)

  アイテム番号 item がヒットされた時に呼ばれます。トグルボタンなどの再描画は自分で処理してください。