画面に描画をしてみよう - 2 / 3 -
BREW に用意されているインターフェイス
BREW に用意されているインターフェイスにはどのようなものがあるか、調べてみましょう。 BREW SDK の「 BREW API リファレンス」を開いてみましょう。 HTML ヘルプ (あるいは PDF ) の左側の目次に、たくさんのインターフェイスが並んでいるのが分かるでしょう。
試しに、 IFileMgr インターフェイスを調べてみてください。これは、携帯電話上のファイルシステムにアクセスするためのインターフェイスです。例えば IFILEMGR_OpenFile() 関数を使うと、ファイルを作成したり、読み書きすることができます。
オブジェクトの作成と取得
それでは、 IFileMgr オブジェクトはどのようにして作成したらよいでしょうか。 IShell オブジェクトや IDisplay オブジェクトは、アプレット構造体である AEEApplet が保持しており、すでに作成されているものでした。
それ以外のインターフェイスのオブジェクトは、 IShell の ISHELL_CreateInstance() 関数により作成することができます。
int ISHELL_CreateInstance ( IShell* pIShell, // IShell オブジェクト AEECLSID cls, // 作成するオブジェクトのクラス ID void** ppobj // オブジェクトが返される )
第 2 引数にはクラス ID を指定します。 BREW アプレットのクラス ID と同様に、すべての BREW インタフェースにはクラス ID が割り当てられています。
インターフェイスのクラス ID の一覧は、「BREW API リファレンス」の末尾のほうにある「AEECLSID リスト」で見ることができます。あるいは、 BREW SDK をインストールしたフォルダ内の inc\AEEClassIDs.h ファイルに定義されていますので、これを見ることもできます。
*ただし、この両方にも記載されていないクラス ID もあります。例えば AEECLSID_3D は AEE3D.h で定義されており、ドキュメントには記述されていません。
基本的に、 AEECLSID_ にインターフェイス名の大文字を連結したものがクラス ID を表す定数となります。例えば、 IBitmap のクラス ID は AEECLSID_BITMAP、 IDatabase のクラス ID は AEECLSID_DATABSE となります。
例として、 IFileMgr オブジェクトを作成するコードを以下に示します。
IFileMgr* filemgr; ISHELL_CreateInstance(shell, AEECLSID_FILEMGR, &filemgr);
ISHELL_CreateInstance() 以外にもオブジェクトを取得できる関数があります。例えば、 IFileMgr インターフェイスの IFILEMGR_OpenFile() 関数により、 IFile オブジェクトを取得することができます。
IFileMgr* filemgr; IFile* file; ISHELL_CreateInstance(shell, AEECLSID_FILEMGR, &filemgr); file = IFILEMGR_OpenFile(filemgr, "sample.txt", _OFM_READ);
このように、「BREW API リファレンス」に記載されているインターフェイスのオブジェクトは、 IShell インターフェイスで作成するか、あるいは別のインターフェイス関数を呼び出すことで取得できるようになっています。
上記のようなファイルシステムにアクセスするインターフェイスを使用する場合、 MIF ファイルの [全般] タブの [特権レベル] で [ファイル] を選択しなければ動作しません。
オブジェクトの破棄
オブジェクトの作成の方法は分かりました。ではオブジェクトの破棄はどのようにするのでしょうか。オブジェクトを破棄することができなければ、オブジェクトがどんどん増えつづけてメモリを食い尽くしてしまうはずです。
BREW では、オブジェクトの寿命管理に "参照カウント法" を用います。BREW のオブジェクトは、 "参照カウント" と呼ばれる整数を保持しており、 IXXX_AddRef() 関数を呼び出すことで参照カウントが1つ増え、 IXXX_Release() 関数を呼び出すことで参照カウントが1つ減り、参照カウントが 0 になった段階で、オブジェクトは破棄されます(ここで IXXX はインターフェイスの名前です)。
インターフェイス関数を使用してオブジェクトを取得するとき、オブジェクトの参照カウントが一つ増えた状態で返されるため、そのオブジェクトが不要になったときに IXXX_Release() 関数を呼び出す必要があります。
具体例を示しましょう。下記のコードは、 BREW でファイルを読み取るときの一般的なコードを示しています。まず、 ISHELL_CreateInstance() により IFileMgr オブジェクトを作成し、 IFileMgr の IFILEMGR_OpenFile() により IFile オブジェクトを作成します。
それぞれのオブジェクトは、作成したときに参照カウントが 1 つ増えますので、オブジェクトが不要になったら、それぞれの IXXX_Release() を呼び出すことで、参照カウントを一つ減らしています。減らしたときに参照カウントが 0 になればオブジェクトは破棄され、メモリ上から削除されます。
void ReadFileSample(AEEApplet* app) { IShell* shell = app->m_pIShell; IFileMgr* filemgr; IFile* file; // IFileMgr オブジェクトを作成する。 // この段階で IFileMgr オブジェクトの参照カウントが 1 増える。 ISHELL_CreateInstance(shell, AEECLSID_FILEMGR, &filemgr); { // IFile オブジェクトを作成する。 // この段階で IFile オブジェクトの参照カウントが 1 増える。 file = IFILEMGR_OpenFile(filemgr, "sample.txt", _OFM_READ); { // ここで file からデータを読み取る。 } // IFile オブジェクトが不要になったので Release() を呼び出して // 参照カウントを 1 つ減らす。 // ここでもし参照カウントが 0 になったら、 // オブジェクトは実際に破棄される。 IFILE_Release(file); } // 同じく IFileMgr オブジェクトの参照カウントを 1 つ減らす。 IFILEMGR_Release(filemgr); }
参照カウントとは、「そのオブジェクトを必要としている者の数」です。必要としている者がいなくなれば、オブジェクトは自動的に破棄されます。一般に C/C++ 言語では「そのオブジェクトを誰が破棄するのか」という問題が常につきまといますが、参照カウント法を使えば、この問題を気にかける必要がなくなります。
BREW の参照カウントのメカニズムは、 Windows の COM インターフェイスとまったく同じです。 Windows の COM プログラミングを経験された方であれば、容易に理解できることでしょう。
Java では「そのオブジェクトを誰が破棄するのか」問題に対処するために、言語自体にガーベージ コレクションという機能が備わっているため、プログラマーは全く気にする必要がありませんでしたが、 Java も内部的には BREW と同じような管理を行っています。
IGraphics インタフェース
IDisplay インターフェイスを使った描画の方法については理解できたでしょうか。 AEEApplet から IDisplay オブジェクトを取得し、 IDisplay インターフェイスの関数により描画処理を行い、最後に IDisplay_Update() を呼び出すことで、実際の画面に反映させる、たったこれだけです。
しかし、「BREW API リファレンス」をよく調べてみると、 IDisplay では長方形や直線など、単純な図形しか描画できないことが分かるでしょう。
BREW 2.0 以降では、描画用のインターフェイスとして、 IDisplay に加えて IGraphics が提供されています。このインターフェイスでは、円、円弧、扇形、楕円、楕円弧、三角形、角丸四角形、多角形など、多彩な図形を描画できるようになっています。またクリッピング、相対座標描画、ビューポートなど複雑な描画処理もサポートしています。
IGraphics による描画のサンプルを以下に示します。
void GraphicsSample(AEEApplet* app) { IGraphics* graphic; AEECircle circle; // IGraphics オブジェクトの取得 ISHELL_CreateInstance(app->m_pIShell, AEECLSID_GRAPHICS, &graphic); // 背景を白でクリア IGRAPHICS_SetBackground(graphic, 255, 255, 255); // 背景色は白 IGRAPHICS_ClearViewport(graphic); // 画面全体を 背景色で塗りつぶす // 赤い円を描く circle.cx = 50; // 円の中心の X 座標 circle.cy = 50; // 円の中心の Y 座標 circle.r = 20; // 円の半径 IGRAPHICS_SetColor(graphic, 255, 128, 0, 0); // 境界線は橙色 IGRAPHICS_SetFillMode(graphic, TRUE); // 円の中を塗りつぶす IGRAPHICS_SetFillColor(graphic, 255, 0, 0, 0); // 円の中は赤色 IGRAPHICS_DrawCircle(graphic, &circle); // 円を描画する // 画面ビットマップへの描画を実際に表示する IGRAPHICS_Update(graphic); // IGraphics オブジェクトの解放 IGRAPHICS_Release(graphic); }
IGraphics は、 IDisplay のように AEEApplet 構造体がすでに保持しているオブジェクトではないので、 IShell を利用してオブジェクトを作成する必要があります。また、オブジェクトを作成したら必ず解放する必要があります。
その他の描画操作は、上記コードのコメントを見るとすぐにお分かりでしょう。インターフェイス関数の詳細については、「BREW API リファレンス」を参照してください。