タイトル【小池邦人のプログラミング日記】2001/3/17<NibベースのCarbonアプリを作る その3>カテゴリーProjectBuilder/Interface Builder, Carbon/CF, 小池邦人のプログラミング日記
作成日2001/3/17 19:11:8作成者小池邦人
今回は、IBCarbonExampleサンプルプロジェクトのmain.cソースファイルの内容を調べ、どのような仕組みでアプリケーションが成り立っているのかを見てみます。

ADCのSelect&Premierメンバーには「例の物」が到着していると思います。まあ、プログラマーの立場から色々と言いたいこともあるのですが、あと一週間だけ我慢することにしましょう(笑)。肝心のCarbonLibの方は「CarbonLib 1.3d6 SDK」から進展がありません。現在、Carbon Event Modelについて色々とチェックをしている最中なのですが、このモデルの環境下でNavigation Serviceを使うと、ポップアップメニューで上位階層(フォルダやボリューム)へ移動できないという不具合に遭遇してしまいました(私だけ?)。この調子だと、Carbon Event Modelに対応したCarbonアプリケーションが登場するのも、秋口ぐらいに遅れそうですね。WWDC 2001への日本からのツアー内容も発表されましたので、今から気合いを入れて「5月のためのプログラマーの主張」を準備しようと思っています。

さて、前回から紹介しているIBCarbonExampleサンプルプロジェクトのソースファイルは、main.c たったひとつです。プアプリケーションの内容も、表示されたウィンドウ内のコントロールを操作するだの単純な物なので、ソースコード量もこの程度ですみます。ユーザがコントロールを操作した時の対応処理が記述されているのは、タブコントロールのみとなっています。その他のコントロールは、操作は可能なのですが、それにより何か意味のある機能が実行されることはありません。main.cで用意されているルーチンは全部で5つです。そのうちの一つは、ユーザのタブ選択で発生するCarbon Eventを処理するためのHandlerルーチンです。

最初に紹介するのは、アプリケーションへの入り口main()ルーチンです。

 

まず、CreateNibReference()によりmain.nibファイルを指定し、アクセスパスを確保するためのリファレンス(IBNibRef)を得ます。ファイル名を渡す時に使っているCFSTR()は、通常のC文字列をUnicodeベースの文字列に変換するマクロで、Universal InterfacesのCFString.hに定義されています。この処理は、リソースファイルをオープンしてカレントに指定する方法と似ています。しかし、Resource Managerには、アクセスパスを得るためにリファレンスを使うという仕組みはなく、カレントリソースファイルの変更で、どのファイルのどのResourceへのアクセスを優先するのかを決めていました。続いて、CreateNibReference()で得たリファレンス(nibRef)をMakeMenu()とMakeWindow()に渡し、Nibファイルに登録されている情報からメニューバーとウィンドウを作ります。この両ルーチンの内容は、後ほど紹介します。この作業が終了したら、DisposeNibReference()でNibファイルへのリファレンスを解放してしまいます。

GetControlByID()は、ControlIDのID番号とシグネイチャ(OSType)により、お望みのコントロールのControlRefを得るためのAPIです。ID番号とシグネイチャは、Nibファイル作成時に、InterfaceBuilderで割り当てておくことができます。ここでは、TAB_ID=128、TAB_SIGNATURE=‘tabs’を指示し、タブコントロールのControlRefを得ています。続いてInstallEventHandler()により、このコントロールのためのCarbon Event Handlerを実装します。このHandlerが受け取ることのできるCarbon Eventの種類は「kEventControlHit」(指定コントローラがクリックされると発生)のみであり、ルーチンのエントリー名はtabEventHandler()です。次のselectItemOfTabControl()は、ウィンドウ初期表示として、1番目のタブが選択された状態を指示しています。このルーチンの内容も、後ほど詳しく紹介します。最後にRunApplicationEventLoop()を実行し、Carbon Event Loopを開始します。それ以降のユーザの操作内容は、用意されているHandlerルーチンに、すべてCarbon Eventとして配信されます。

MakeMenu()は、アプリケーションのメニューバーを作るルーチンです。

 

SetMenuBarFromNib()にNibファイルのリファレンスとタイトル("MainMenu")を渡し、抽出した情報からメニューバーを作成します。もし、Mac OS 9とMac OS Xの両方で起動できるアプリケーションを開発していれば、この位置でどちらの環境下なのかを調べ、呼び込むメニューバーを変える必要があります。もう片方のMakeWindow()は、アプリケーションのウィンドウをオープンするためのルーチンです。

 

CreateWindowFromNib()にNibファイルのリファレンスとウィンドウタイトル("MainWindow")を渡し、抽出した情報からウィンドウを作成します。処理が成功すると、完成したウィンドウのWindowRefが返りますので、それを使いShowWindow()を実行します。SetPort((GrafPtr)GetWindowPort(myWindow))の箇所は、SetPortWindowPort( myWindow )と記載した方が美しいでしょう。どちらのルーチンも、エラーが起こると、ExitToShell()でアプリケーションを強制終了しています。

selectItemOfTabControl()ルーチンは、ユーザがタブを選択した時の表示切り替えを受け持ちます。

 

ソースコード自体はちょっと変な記述となっていますが(笑)、要は、各タブに属するコントロールの表示状態を、SetControlVisibility()により一括で切り替えているわけです。SetControlVisibility()に渡しているControlRef(userPane)は、タブに属するコントロールの上位コントロールの物だと思えば良いでしょう。このContolRefを得るためのcontrolIDの内容(User Pane Signature=‘tabs’ User Pane ID=129と130)は、先んじてInterfaceBuilderのインスペクターでタブごとに設定されています。

 

最後にDraw1Control()でタブコントロール自体を再描画し、表示切り替え作業は完了します。

tabEventHandler()は、タブコントロールのクリックで発生したCarbon Eventを処理するためのHandlerルーチンです。

 

処理は非常に簡単で、main() と同じ方法でタブコントロールのContolRefを得て、GetControlValue()で選択されたタブ番号を調べます。もしそれがlastTabIndexと異なっていれば、selectItemOfTabControl()を呼び出してタブ表示を切り替えます。この比較で使われている外部変数のllastTabIndexは、selectItemOfTabControl()でセットされている「現在選択されているタブ番号」です。

以上のように、このアプリケーションではタブの切り替えのみが処理されていることが分かります。しかし実際にアプリケーションを動かしてみると、他のコントロール操作(クリック、ドラッグ、キー入力)も可能となっています。つまり、タブ以外のコントロールについては、ディフォルトのCarbon Event Handlerが処理しているわけです。例えば、メインウィンドウには「Quit」ボタンがありますが、これに対してアプリケーション側ではHandlerを用意していません。ところが、このボタンをクリックすると、アプリケーションはちゃんと終了します。InterfaceBuilderで調べると、このボタンにはメニューなどで用いるハイコマンド(‘quit’)が割付けられていることが分かります。よって、アプリケーション側で何も処理をしなくても、ディフォルトHandlerが適切に処理を実行してくれるわけです。

次回は、いったんNibベースのCarbonアプリケーションの話しを中断し、正式に発表されているはずの「Mac OS X」についての第一印象を述べてみたいと思います。
[小池邦人/オッティモ]
関連リンクオッティモ