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* がヒットされた時に呼ばれます。トグルボタンなど
   の再描画は自分で処理してください。
