ユ−ザインタフェ−スを実装する

prev.

まだかきかけよん。

概要

palmwareにおいても、GUIをつかさどるフォ−ムやラベルなどは、実行コードとは別にリソースとして用意する。また、フォームをタップしたり、ジョグダイアルを廻したり、電源ボタンを押したりするのは、すべてイベントとしてイベントキューに入れられる。これらを適切に処理してやることで、GUIを用いたアプリケーションを実装していく。
このページでは、リソースを prcファイルに組みこむ方法、ロジックからリソースを利用する方法、イベント処理の基本パターンについて説明する。

リソースをprcに組みこむ

具体的な作業内容は、以下のようになる:

  1. リソース定義ファイルを用意する。
  2. リソースコンパイラを用いてコンパイルし、リソースバイナリを作成する。
  3. 同時に、a.outをコードリソースバイナリに変換する。
  4. リソースバイナリを結合し、prcファイルを作成する。

アプリケーションを起動すると、画面全体をフォームで覆い、中央に "Hello World!" という文字列を表示し、画面中央のボタンを押すと電源を切り、アプリケーションアイコンをタップすると終る。そんなアプリを作成してみよう。

リソース定義ファイルを用意する

リソースの定義の仕方は、開発環境によって異なる。このページではgcc系を使った PRC-Tools の環境なので、リソースは rcpという拡張子を持つテキストファイルで定義する*
rcpのファイルフォーマットについては、 pilrc_src.tgz を展開したディレクトリの doc/manual.htmlファイルに書いてある。ここではサンプルとして、画面全体を覆うFormと、その中央に配置したボタンを定義しよう:

FORM ID 1000 AT (0 0 160 160) USABLE BEGIN TITLE "Hello, World" BUTTON "POWEROFF" ID 1001 AT (CENTER 130 AUTO AUTO) END

これを、例えば MyFirstApp.rcp というファイル名で保存する。

*CodeWarrior環境では、Resource.frk/*.rsrc というファイルで提供される。どっかで見たことあるかも。

コンパイル、ビルドする

こんな感じ。

% pilrc MyFirstApp.rcp PilRC v2.9 Copyright 1997-1999 Wes Cherry (wesc@ricochet.net) Copyright 2000-2001 Aaron Ardiri (aaron@ardiri.com) Generating 68K resources from 'MyFirstApp.rcp'. Writing tFRM03e8.bin 170 bytes % m68k-palmos-gcc -g MyFirstApp.c % build-prc -c test -n test a.out *.bin

最初のpilrcで、リソース定義ファイルをリソースバイナリにする。 この時点で、 tFRM03e8.bin というファイルが出来る。
その次に、Cソースファイルをコンパイルし、mc68k COFF object という型式の a.out というファイルを作成している。
最後で、a.outからコードリソースを取りだし、さっき作った tFRM03e8.binと一緒に束ねて、a.prc という名前の PalmOS application ファイルにしている。*
なお、この段階では、リソースを利用するコードを書いていないので、動かしてみても変化はない。

*ここでは手順を省略しているが、よりこまかくステップを踏むなら、以下のようになる:

% pilrc MyFirstApp.rcp % m68k-palmos-gcc MyFirstApp.c % m68k-palmos-obj-res a.out % build-prc *.bin *.grc それぞれの段階でどのようなファイルを生成しているか、確認しておこう。


リソースを利用するコードを書く

フォームリソースを表示してみよう。

FrmGotoForm(1000);

とすると、フォームリソースがロードされオープンされる。それぞれのあと、 frmLoadEvent, frmOpenEventが発生するので、frmOpenEventを受けたら FrmDrawForm(event.data.formID);を実行してやると、OS側で適切に描画してくれる。
以下のようなコードを、MyFirstApp.cのようなファイル名で保存しておく:

#include <PalmOS.h> /* * フォーム固有の処理を行なうイベントハンドラ */ static Boolean mainFormEventHandler(EventType *event) { FormPtr formP; Boolean handled = false; switch (event->eType) { case frmOpenEvent: formP = FrmGetActiveForm(); // アクティブなフォームを FrmDrawForm(formP); // 描画する handled = true; break; case ctlSelectEvent: // 画面のボタンが押されたら SysSleep(false,false); // 電源を切る break; default: break; } return handled; } /* * アプリケーション固有の処理を行なうイベントハンドラ */ static Boolean AppHandleEvent(EventType *event) { FormPtr formP; Boolean handled = false; switch (event->eType) { case frmLoadEvent: formP = FrmInitForm(event->data.frmLoad.formID); // フォームを初期化して FrmSetActiveForm(formP); // アクティブに指定して FrmSetEventHandler(formP, mainFormEventHandler); // イベントハンドラを設定 handled = true; break; default: break; } return handled; } /* * エントリポイントはココ */ UInt32 PilotMain(UInt16 cmd, void *cmdPBP, UInt16 launchFlags) { EventType event; FormPtr formP; Err err; Boolean handled = false; if(cmd != sysAppLaunchCmdNormalLaunch) return 0; FrmGotoForm(1000); // フォーム1000に移動 do { EvtGetEvent(&event,evtWaitForever); SysHandleEvent(&event) || // システム規定の処理を行ない AppHandleEvent(&event) || // アプリ固有の処理を行ない FrmDispatchEvent(&event); // フォーム固有の処理を行なう } while (event.eType != appStopEvent); FrmCloseAllForms(); }

でき上がったら、動かしてみよう。 定義したフォームが画面に表示され、ホームアプリをタップすれば終了する。

ソース解説

アプリを起動すると、三つめのPilotMain関数が呼び出される。ここで、まず ID=1000 なフォームへの移動を指示する。
その次の do ... while がイベントループである。まず、イベントキューからイベントをひとつ取りだす。そして、SysHandleEvent でイベント処理を試みる。ホームシルクをタップしたり、予定表ボタンを押したりといったイベントであれば、SysHandleEventはなんらかの処理を行なった上で、 true をかえす。そうでなければ false をかえす。
falseがかえった場合、AppHandleEvent でイベント処理を試みる。AppHandleEventはこのファイルで定義している二つめの関数であるが、これもSysHandleEventと同様、なんらかの処理を試み、処理を行なったら true をかえす。そうでなければ false をかえす。

ここでいったん、二つめの関数に目を移そう。AppHandleEventは、frmLoadEventだけを処理する。frmLoadEventを受け取ったら、指定されたフォームを初期化し、それをアクティブに指定し、そのフォームに対するイベントハンドラを指定する。ここでは、イベントハンドラとして、一つめのmainFormHandleEvent関数を指定した。これらの処理を行なった上で、true をかえす。そうでなければ(なにも処理を行なわなければ) falseをかえす。

さて、またPilotMainに目を戻そう。SysHandleEvent, AppHandleEventのどちらも処理を行なわず、それぞれ false がかえってきた場合、FrmDispatchEvent をとおして、一つめの mainFormHandleEvent を呼び出す。

ここで一つめの mainFormHandleEventを見てみよう。この関数はmainFormに関するイベントハンドラであり、frmOpenEventを受け取ったらフォームを描画し、またctlSelectEventを受け取ったら、SysSleep関数を呼び出す、という処理を行なった上で true をかえす。

上記のようなしくみで、描画された"POWEROFF"ボタンがタップされたら、SysSleep すなわち電源を切る、という動作をすることとなる。

リソースを使うメリット


Last Modified: Sept. 30, 2002. Copyright © 2002 by matobaa.