iアプリの基本がわかったところで、もうちょっと部品のあるiアプリを作ってみましょう。Javaのawtの基本的なコンポーネントは皆さんなじみですから、それに近い感覚で扱えるものをいくつか利用してみます。まず、簡単なところで「整数を入力してボタンを押すと、1〜その数字までの合計を計算して表示する」というものを作ってみましょう。――え? 誰ですか、「なんかワンパターンなプログラムだな」なんていう人は。テキストを表示する部品と、計算と、繰り返しなどの構文を使ったわかりやすいサンプルとしては定番なんですよこれは(他に思いつかないし)。
import com.nttdocomo.ui.*;
public class Test2 extends IApplication {
public void start() { Display.setCurrent(new Test2Frame(this)); }
}
class Test2Frame extends Panel implements SoftKeyListener { IApplication app; Label l1; TextBox t1;
public Test2Frame(IApplication a){ app = a; setTitle("Calculate"); setSoftLabel(Frame.SOFT_KEY_1, "Exit"); setSoftLabel(Frame.SOFT_KEY_2, "CALC"); setSoftKeyListener(this); t1 = new TextBox("0",10,1,TextBox.NUMBER); add(t1); l1 = new Label("ENTER NUMBER."); add(l1); }
public void softKeyReleased(int softKey) { switch(softKey){ case Frame.SOFT_KEY_1: app.terminate(); break; case Frame.SOFT_KEY_2: try { int n = Integer.parseInt(t1.getText()); int x = 0; for(int i = 0;i <= n;i++) x += i; l1.setText("Total: " + Integer.toString(x)); } catch(Exception ex) {l1.setText("Not number.");} break; } }
public void softKeyPressed(int softKye){}
}
これが、計算iアプリのソースコードです。見ればわかるように、「Test2」というIApplicationクラスと、Panel継承の「Test2Frame」クラスからなっていますね。基本的な形は前回のものと同じですからそう違和感はないでしょう。
作成したら「Test2.java」という名前で保存し、コンパイルします。先に触れましたが、com.nttdocomoパッケージをクラスパスに含めるのを忘れないように。できあがったら、とりあえずJARやJAMといったファイルの作成はおいといて、i-JADEのエミュレータで動かしてみましょう。
これがその画面です。起動すると、「0」と表示されたエリアが選択された状態で現れます。これで、「決定」ボタン(上下左右にカーソル移動するボタンのど真ん中にあるやつ)を押すと、画面にテキスト入力用の表示が現れます。ここで親指を駆使して数字を入力して「決定」ボタンを押せば、ちゃんと入力した数字が設定されます。いや〜しかし、携帯の親指によるテキスト入力をマウスクリックでやるってのは想像した以上に苦痛ですねぇ…。
後は、右上のソフトキー(「CALC」)を押せば、その数字までの合計が計算され、入力した数字の下に表示されます。もし数字以外のものを入力すると、ちゃんと「Not Number」と表示されます。そして左上のソフトキーを押せばiアプリは終了です。――どうです、iアプリったって、ゲームばっかりじゃなくて、実用ソフト(というと大袈裟だけど)も作れるんですよ。
では、 コードを見てみましょう。IApplication部分についてはほとんど違いはないので省略します。画面に表示されているTest2Frameクラスでは、コンストラクタでコンポーネントの組み込みを行ない、softKeyReleasedメソッドで計算の処理を行なっています。
まず、最初にクラス変数の宣言がずらりと並んでいますね。以下のような感じの部分です。
class Test2Frame extends Panel implements SoftKeyListener { IApplication app; Label l1; TextBox t1;
ここで、「Label」「TextBox」という2つのコンポーネントのインスタンスを宣言しています。これらはお馴染みのものですが、もちろんawtではなくcom.nttdocomoのクラスです。そしてコンストラクタで、これらのコンポーネントを組み込んでいます。
public Test2Frame(IApplication a){ app = a; setTitle("Calculate"); setSoftLabel(Frame.SOFT_KEY_1, "Exit"); setSoftLabel(Frame.SOFT_KEY_2, "CALC"); setSoftKeyListener(this); t1 = new TextBox("0",10,1,TextBox.NUMBER); add(t1); l1 = new Label("ENTER NUMBER."); add(l1); }
後半の部分が、インスタンスの生成と組み込みです。「new TextBox」と「new Label」でインスタンスを生成し、「add」で組み込んでいます。感覚的にはawtとそっくりですね。TextBoxのnewがやたらパラメータが多いの目をひきます。このTextBoxでは、「表示するテキスト、表示する文字数、行数、モード」の4つをパラメータで指定する必要があります。最後の「モード」というのは、デフォルトの入力モード(要するに日本語かアルファベットか数字かといったもの)を指定するためのもので、これにはTextBoxクラスに用意されている「ALPHA」「KANA」「NUMBER」といったもので指定します。――が、やってみたところ、数字モードになるはずなのに、P503iエミュレータではなぜか入力時に「かな」モードになってしまいました。これでいいはずなんですが…。
また、TextBox.KANAを指定すると、うちのN503iではプログラムが実行できませんでした。TextBox.DISPLAY_ANYというのを指定すると漢字入力モードで表示されたので、日本語を利用する時はこれにしておくのがいいでしょう。
Labelのほうはわかりますね。ラベルに表示するテキストをパラメータに指定してnewしているだけです。addも簡単で、単に組み込むコンポーネントをパラメータ指定するだけ。こうすると、addした順番に表示されます。このPanelでは、アプレットなどと同様にFlowLayoutと同じ感覚でコンポーネントがレイアウトされるようです。
では、実際の計算を行なっているsoftKeyReleasedメソッドを見てみましょう。
public void softKeyReleased(int softKey) { switch(softKey){ case Frame.SOFT_KEY_1: app.terminate(); break; case Frame.SOFT_KEY_2: try { int n = Integer.parseInt(t1.getText()); int x = 0; for(int i = 0;i <= n;i++) x += i; l1.setText("Total: " + Integer.toString(x)); } catch(Exception ex) {l1.setText("Not number.");} break; } }
こちらも、case Frame.SOFT_KEY_1:については先のコードと全く同じですね。計算をしているのはcase Frame.SOFT_KEY_2:の部分です。ここでは、まず「Intere.parseInt」で「t1.getText()」の値をint値に変換しています。com.nttdocomoでもIntegerクラスなどは同じですし、コンポーネントのテキストを操作するのに「getText」「setText」といったメソッドを使う点も同じです。そしてforを使って計算を行ない、結果をInteger.toStringでStringに変換してl1にsetTextしています。数字以外のものが入力されていたことを考え、try構文を使い、エラーが起きたらcatch部分で「Not Number.」と表示させるようにしてあります。
これで、LabelとTextBoxのテキストを操作したり、整数とテキスト間で値を変換したりする基本はわかりました。これだけわかれば、簡単な計算iアプリは十分作れるようになりますよ!
もう1つ、コンポーネントを使った例をあげておきましょう。今まで処理を実行するにはソフトキーを使ってきましたが、実はcom.nttdocomo.uiにもボタンはあります。ただ、これはちょっとだけイベント処理の方法(というかリスナーの使い方)が違っています。そこで、「ティッカー」と呼ばれるちょっと面白いコンポーネントを使って、これらの基本を説明しておくことにしましょう。
import com.nttdocomo.ui.*;
public class Test3 extends IApplication {
public void start() { Display.setCurrent(new Test3Frame(this)); }
}
class Test3Frame extends Panel implements SoftKeyListener,ComponentListener { IApplication app; TextBox tb1; Button b1; Ticker tk1;
public Test3Frame(IApplication a){ app = a; setTitle("Ticker !"); setSoftLabel(Frame.SOFT_KEY_1, "Exit"); setSoftKeyListener(this); tb1 = new TextBox("Welcome",15,1,TextBox.NUMBER); add(tb1); b1 = new Button("Set"); add(b1); tk1 = new Ticker(); add(tk1); setComponentListener(this); }
public void componentAction(Component cp, int type, int param) { if (cp == b1 && type == BUTTON_PRESSED) { tk1.setText(tb1.getText()); } }
public void softKeyReleased(int softKey) { switch(softKey){ case Frame.SOFT_KEY_1: app.terminate(); break; } }
public void softKeyPressed(int softKye){}
}
これがソースコードです。これを「Test3.java」として保存し、コンパイルして下さい。そしてi-JADEエミュレータで実行します。――これは、入力したテキストを右から左へアニメーションしながら表示する(いわゆるマーカー機能)プログラムです。先ほどと同じ要領でTextBoxにテキストを入力し、カーソルを「Set」というボタンに移動して決定すれば、そのテキストが画面の右からゆっくりと左へ移動していきますよ。
ここでも、IApplication部分にはほとんど違いはなく、Test3Frameクラスがポイントとなります。ここではTextBoxの他に「Button」と「Ticker」というコンポーネントを使います。Buttonがボタンのクラスで、Tickerというのがマーカー表示をするコンポーネント(ティッカーといいます)のクラスです。
では、ソースコードを見ていくことにしましょう。今回は、単にコンポーネントだけでなく、新しいリスナーも登場しますから、頑張って覚えましょう。――まず、Test3Frameクラスの最初の部分を見て下さい。
class Test3Frame extends Panel implements SoftKeyListener,ComponentListener { IApplication app; TextBox tb1; Button b1; Ticker tk1;
コンポーネントの宣言が増えているのはいいとして、よく見るとimplementsしているものも増えてますね。「ComponentListener」というのが追加されました。これが、コンポーネントを操作した際に発生するイベントを処理するためのリスナーなのです。Buttonやその他の画面に表示されているコンポーネントで何か操作がされると、このリスナーが処理を行ないます。
public Test3Frame(IApplication a){ app = a; setTitle("Ticker !"); setSoftLabel(Frame.SOFT_KEY_1, "Exit"); setSoftKeyListener(this); tb1 = new TextBox("Welcome",15,1,TextBox.NUMBER); add(tb1); b1 = new Button("Set"); add(b1); tk1 = new Ticker(); add(tk1); setComponentListener(this); }
さて、コンポーネントの組み込みをやっているコンストラクタを見てみましょう。Buttonは、表示するテキストをパラメータに指定するだけですね。そしてTickerというものは、何もパラメータを持ちません(本当は、表示するテキストを最初からパラメータに指定することもできます)。
問題はその後です。「setComponentListener(this);」として、リスナークラス(ここでは自分自身)を設定しています。しかし、どこか変な感じがしませんか? そうです、これはPanelクラスを継承したTest3Frame自身にsetされているのです。Buttonをクリックした時に実行して欲しいのに、なぜPanelに? 普通は、リスナーというのは、ボタンのイベントならボタンに設定するはずではありませんか。
実をいえば、ここがcom.nttdocomoのuiの不思議なところなのです。503iでは、コンポーネントのイベントを処理するリスナーは、コンポーネントが組み込まれているコンテナ側にsetするのです。各コンポーネントに個別にリスナーを組み込むことはできません。――こうすると、そのコンテナ及びそこに組み込まれているコンポーネントでイベントが発生すると、全てこのリスナーがまとめて処理するようになるのです。
そして、このComponentListenerに用意されているメソッドが「componentAction」というものです。リスナーが組み込まれたコンテナ及びそこにaddされたコンポーネントでイベントが発生すると、ComponentListenerをimplementsされたクラスのcomponentActionが呼び出されるようになっています。
public void componentAction(Component cp, int type, int param) { if (cp == b1 && type == BUTTON_PRESSED) { tk1.setText(tb1.getText()); } }
これが、そのメソッドですね。このcomponentActionメソッドは、3つのパラメータを持っています。1つは、イベントが発生したコンポーネントの参照、2つ目がイベントのタイプを示す値、3つ目がイベント独自のパラメータとなります。この3つ目は、コンポーネントによって使ったり使わなかったりします。
ここでは、まず発生したコンポーネントがb1かどうか調べ、更にイベントのタイプがボタンをプレスした際のものかどうかを調べています。イベントのタイプはComponentListenerに用意されている値を使います。ここで比較している「BUTTON_PRESSED」は、文字通りボタンをプレスした時のイベントを示す値です。この他、ListBoxという一覧リストで選択変更した際の「SELECTION_CHANGED」、テキストを変更した際の「TEXT_CHANGED」といったものがあります。
そして両者が成立するならば、TickerインスタンスにsetTextでTextBoxのテキストを設定しています。Tickerは、このように単にsetTextするだけで、そのテキストを自動的に右から左へとエンドレスに動かしてくれます。非常に単純ですが、使い方によってはけっこう重宝するコンポーネントですね。
以上で、基本的なコンポーネントいくつかを利用できるようになりました。ここまでくれば、簡単なiアプリは作れるはずです。それぞれでオリジナルiアプリに挑戦してみると面白いですよ!