• 検索結果がありません。

低レベルAPIによるプログラミング

第 4 章 ユーザーインタフェースの設計

4.2 低レベルAPIによるプログラミング

ゲームアプリケーションなどの分野では、コンポーネントを使用したユーザーインタフェースより もグラフィックス描画機能を多用する場合があります。この節では、主にグラフィックス描画を行 うための低レベル API の使い方とイベントの処理方法について説明します。

4.2.1 Canvas の使用

Canvas は、グラフィックスを描画するための画面領域です。開発者は Canvas クラスのサブクラ

スを作成し、 paint()メソッドをオーバーライドすることによって、 Canvas に描画することがで

きます。paint()メソッドは、システムが Canvas の描画が必要と判断したときやアプリケーシ

ョンプログラムが明示的に再描画を要求したとき(repaint()メソッドを呼び出したとき)にシ

ステムからコールバックされます。

Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.

Panel と同様に、 1 つの Canvas オブジェクトは 1 つの画面に相当します。したがって、1 つの画 面に複数の Canvas を表示したり、Canvas と Panel を同時に 1 つの画面に表示することはでき ません。ただし複数の Canvas や Panel を、1 つの画面上に順次切り替えて表示することは可能 です。

次に Canvas に簡単な描画を行う例を示します。

例: Canvas への描画

import com.nttdocomo.ui.*;

public class CanvasDemo extends Canvas { int x = 20;

int y = 10;

CanvasDemo() {

// ソフトキーラベル「back」を作成する。

setSoftLabel(Frame.SOFT_KEY_1, "Back");

}

/**

* キャンバス領域に文字列と矩形を描画する。

*/

public void paint(Graphics g) { g.lock();

g.clearRect(0, 0, 1000, 1000);

g.drawString("Hello", x, y);

g.drawString("Canvas", x, y+15);

g.drawRect(x+10, y+30, 20, 5);

g.unlock(true);

}

}

注意事項:

● repaint()メソッドはシステムに対し描画の必要があることを指示するためのものであり、1回の repaint()メソッド呼び出しが1回のpaint()メソッド呼び出しに対応することを保証するものではあり ません。このためアプリケーションプログラムから見た場合に、複数の連続したrepaint()メソッド呼び 出しが1回のpaint()メソッド呼び出しにまとめられることがあります。開発者は、paint()メソッド呼 び出しが1回にまとめられたような場合にも画面の描画が正しく行われるようpaint()メソッドを記述する 必要があります。

● DoJa-3.0プロファイルでは、カレントフレームに設定されていないCanvasに対するrepaint()メソッドの

呼び出しは無視されます。なお、DoJa-2.xプロファイル以前のプロファイルでは、カレントフレームに設定 されていないCanvasに対してrepaint()メソッドを呼び出した場合の振る舞いはメーカーにより異なり ます。

【DoJa-5.0】

DoJa-5.0プロファイル以降、メーカーによってはADFのDrawAreaキーを使用することで、デフォルト

(DrawAreaキー未使用時)の表示領域よりも広い表示領域を使用できる場合があります。そのような機種に は、Canvas.setSoftLabelVisible()メソッドを使用することで、Canvas表示時のソフトキーラベルの 表示のオン、オフを切り替えることができるものがあります。なお、setSoftLabelVisible()メソッドは Frameクラスで定義されたメソッドですが、現在のプロファイルではCanvas以外のフレームオブジェクト

(PanelやDialog)に対してこのメソッドを呼び出すことはできません。

Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.

4.2.2 グラフィックスの描画

線や図形、テキストなどの描画には、グラフィックスオブジェクト(Graphics クラスのオブジェ クト)を使用します。このオブジェクトには描画可能な領域、フォント、色などの情報が含まれて いるため、グラフィックスコンテキストとも呼ばれます。前項の例ではグラフィックスコンテキス ト g を使い、clearRect()メソッドによる画面のクリアの後に drawString()メソッドを呼び 出してテキストを描画し、続いて drawRect()メソッドを呼び出して矩形を描画しています。

上の例で使用している lock()メソッドと unlock()メソッドは、グラフィックス描画のダブルバ ッファリングを管理するために Graphics クラスに用意されているメソッドです。ダブルバッフ ァリング中は、指示された描画はオフスクリーンバッファに対して行われ、ダブルバッファリング 終了とともにオンスクリーンにコピーされます。このため、ダブルバッファリングを使用するとフ リッカーが発生しません。

ダブルバッファリングは、メーカーによりサポートされない場合があります。ダブルバッファリン グをサポートしない機種では、この 2 つのメソッドは何も行いません。ダブルバッファリングをサ ポートするデバイスでは lock()メソッドが呼び出されると(1 回または複数回)、unlock()メ ソッドが引数に true が指定されて呼び出されるか、引数に false が指定されて lock()メソッド呼 び出しと同じ回数だけ呼び出されるまで、画面への描画は一時的に保留されます。

注意事項:

● ダブルバッファリングの実装は携帯電話によって異なります。アプリケーションプログラムの正しい動作を 保証するために、ダブルバッファリングを使用する際は次のガイドラインに従うようにしてください。

• 異なるGraphicsオブジェクトのlock()メソッドとunlock()メソッドの呼び出しを混在して行わ ない。

• paint()メソッドを終了する前には必ずGraphicsオブジェクトのロックを解除する。

次のコードに、ロックおよびロック解除の正しい使い方を示します。

例: 正しい実装(上記ガイドラインに従っている)

import com.nttdocomo.ui.*;

public void paint(Graphics g) { Graphics g2 = g.copy();

g.lock();

// 何かを描画する ...

g.unlock(false);

g2.lock();

// さらに描画する...

g2.unlock(false);

}

次のコードに、ロックおよびロック解除の正しくない使い方を示します。

例: 正しくない実装

import com.nttdocomo.ui.*;

public void paint(Graphics g) { Graphics g2 = g.copy();

g.lock();

// 何かを描画する...

g2.lock(); // gとg2のロック区間が重複している // さらに描画する ...

g.unlock(false); // g2のロック解除が行われていない }

Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.

● システムからコールバックされたpaint()メソッドの引数で渡されるグラフィックスオブジェクトに対し、

Graphics.dispose()メソッドは発行しないでください。この場合のグラフィックスオブジェクトの破棄 は、必要に応じてpaint()メソッドの呼び出し元であるiアプリ実行環境により行われます。また、アプリ ケーションプログラムがCanvasオブジェクトやImageオブジェクトからgetGraphics()メソッドを使 用してグラフィックスオブジェクトを取得した場合、そのグラフィックスオブジェクトが不要になった時点 でdispose()メソッドを呼び出すようにしてください。

● iアプリ実行環境では、repaint()メソッドの引数に矩形領域を設定することで指定された矩形領域のみの 再描画を行うことができます。DoJa-1.0プロファイルでは、描画デバイスの持つクリッピング描画能力によ りこの機能をサポートしない携帯電話があることを想定していますが、DoJa-2.0プロファイル以降に対応し た携帯電話は全てこの機能をサポートします。

● iアプリ実行環境では透過GIFがサポートされており、透過GIFのメディアイメージから生成したイメージ オブジェクトを描画すると透過部分は描画対象外となります。ただしこの効果は透過GIFから生成されたイ メージオブジェクトを描画する際のみであり、その描画結果からは透過情報は失われます。

● DoJa-2.0プロファイルでは、iアプリの中断・再開によりCanvasが再表示される際、iアプリ実行環境か

らそのCanvasのpaint()メソッドが1回呼び出されることが保証されます。しかしそのpaint()メソッ ド呼び出しで全画面が完全には復元されないようなケース(アプリケーションプログラムがイベントに応じ て差分描画のみ行うようになっているなど)では、どの程度システムが画面を復元できるかは機種により異 なります。

なおDoJa-3.0プロファイル以降では、iアプリの再開時にシステムがCanvasの描画内容をすべて復元でき

た場合は、paint()メソッドは呼び出されません。

● DoJa-2.0プロファイルでは、低レベル文字列描画に使用されるデフォルトフォントは12ドットフォントです。

これに対しDoJa-1.0プロファイルでは、デフォルトフォントサイズはメーカーにより異なります。なお、い ずれのプロファイルにおいても、デフォルトフォント以外にどのようなフォントをサポートするかについて はメーカーにより異なります。一般には、携帯電話の限られたメモリにフォント情報を保持する必要がある ため、実際に搭載されるフォントの数は数種類に限られます。DoJa-1.0プロファイルおよびDoJa-2.0プロフ ァイルでは、デフォルトフォントのサイズはFont.SIZE_MEDIUMに対応しています。

なおDoJa-3.0プロファイル以降でも、プロファイル間におけるアプリケーションプログラムの互換性の観点

からデフォルトフォントは12ドットフォントとしています。ただし、携帯電話に搭載されるLCDデバイス の高精細化に伴い、デフォルトフォントのサイズはDoJa-3.0プロファイルにて新設されたFont.SIZE_TINY に対応するよう変更されています。ミディアムフォントはDoJa-3.0プロファイル以降では24ドットフォント となります(タイニー、ミディアム以外のフォントについては、メーカーによりサイズが異なる場合があり ます)。

高精細化の進んだLCDデバイス上では同一ドット数のフォントでも視覚上のサイズは小さくなるため、画面 設計においては状況に応じてより大きなフォントを使用することも検討してください。

【DoJa-5.0】

DoJa-5.0プロファイルにて、既定のフォントサイズ(SIZE_TINY、SIZE_SMALL、SIZE_MEDIUM、

SIZE_LARGE)以外のサイズのフォントをサポートする機種が現れる可能性があります。そのような機

種では、Font.getSupportedFontSizes()メソッドを使用してその機種でサポートしているフォン トサイズのリストを取得することができます(既定のフォントサイズのみサポートする機種ではこのメ ソッドを使用して情報を得ることはできません)。

既定のフォントサイズ以外のフォントについては、DoJa-5.0プロファイルで新設された

Font.getFont(int,int)メソッドを使用して、フォントサイズを数値で直接指定することで、そのサ イズに対応するフォントオブジェクトを取得することができます。

● DoJa-2.0以降の各プロファイルでは、グラフィックス描画に関してiアプリオプションおよびiアプリ拡張

のカテゴリに属する機能(スプライトや3Dグラフィックスなど)が追加で規定されています。これらの詳 細については、「iアプリコンテンツ開発ガイド iアプリオプション・iアプリ拡張編」および「iアプ リコンテンツ開発ガイド オプション・拡張APIリファレンス編」を参照してください。なお、それらの中 には、プロファイルのバージョンアップの過程でiアプリ基本APIに取り入れられたものもあります。

Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.

● DoJa-3.0プロファイル以降では、Canvasに対応付けられているグラフィックスオブジェクトへの描画はそ

のCanvasがカレントフレームに設定されている場合のみ行われます。対応付けられているCanvasがカレ ントフレームに設定されていない場合、そのグラフィックスオブジェクトに対する描画メソッドの呼び出し は無視されます。

4.2.3 Image オブジェクトへの描画

DoJa-2.0 プロファイル以降では、Image オブジェクトへの描画をサポートします。

Image オブジェクトからの Graphics オブジェクトの取得は、 Image.getGraphics()メソッド を呼び出すことにより行います。Image オブジェクトから取得した Graphics オブジェクトへの 描画指示は、元となる Image オブジェクトの表示内容に反映されます。このようにして描画され た Image オブジェクトを ImageLabel や ImageButton に設定することで、アプリケーション プログラムが行った描画処理の結果を Panel 使用時にも表示することができます。

Image オブジェクトから Image.getGraphics()メソッドにより Graphics オブジェクトを取 得するには、その Image オブジェクトが Image.createImage()メソッドにより生成された新 規の Image オブジェクトでなければなりません。MediaImage.getImage()メソッドで取得し た Image オブジェクトに対して getGraphics()メソッドを呼び出した場合、

UnsupportedOperationException がスローされます。

なお、 Image.createImage()で生成されたイメージは、初期状態ではその機種における Canvas のデフォルト背景色と同じ色で塗りつぶされています。ただし Image 自身には背景色の概念はあ りません。Image から取得した Graphics に対して描画内容のクリアを指示するには、

Graphics.clearRect()メソッドではなく、適切な色の設定を行った上で Graphics.fillRect()メソッドを呼び出します。

次のコードは、アプリケーションプログラムからの指示により描画された Image オブジェクトを ImageLabel で使用する例です。

例: Image オブジェクトへの描画

import com.nttdocomo.ui.*;

public class ImageDrawDemo extends UIDemoPanel { ImageLabel iLabel;

Image img;

Graphics g;

ImageDrawDemo() {

// Imageオブジェクトを新規に生成し、Graphicsオブジェクトを取得する。

int width = 100;

int height = 50;

img = Image.createImage(width, height);

g = img.getGraphics();

// 取得したGraphicsオブジェクトに描画する。

g.lock();

g.drawRect(0, 0, width-1, height-1);

g.drawString("Graphicsによる", 5, 16);

g.drawString("Imageへの", 5, 32);

g.drawString("描画のサンプル", 5, 48);

g.unlock(true);

// ImageオブジェクトImageLabelに設定し、Panel上に表示する。

iLabel = new ImageLabel(img);