GO BACK

Cocoa-Java 教室 その2

「ボタンとテキストフィールド」



■Javaのクラスを作成する

 さて、前回はInterface BuilderでNSButtonとNSTextFieldを使ったインターフェイスを設計したところで終りました。次はいよいよ「Javaのソースコード」を記述しましょう。

 が、「ソースコードを記述する」といっても、一体どこに書けばいいんでしょう? Project Builderには、Javaのソースコードファイルなどありませんでした。——そもそも、Javaのソースコードというのはすべて「クラス」として記述するのが基本です。ということは、プロジェクトに新しいJavaのクラスを追加し、そこにソースコードを記述すればいいはずです。

 ただし、このときに忘れてはならないことは「そのクラスは、Cocoaから利用できるように作らないといけない」ということです。例えば、ボタンをクリックしたら何かを実行させたい場合、CocoaのインターフェイスであるNSButtonで発生したイベントにより、Javaのクラス内のメソッドが呼び出される・・といった処理がきちんと機能しないといけません。ということは、単にProject Builderでファイルを追加するだけでなく、Interface Builderで作ったインターフェイスと、何らかの形で連携するような仕組みが用意されてないといけない、ということですね。

 この「インターフェイスとの連携」が必要なJavaクラスは、Project Builderでなく、Interface Builderでクラスを作成します。これはちょっとわかりにくいので、順番に作業していきましょう。

1.まず、Nibファイルウィンドウで「Classes」タブを選択します。これは、利用可能なクラスのリストを表示するものです。

2.リストの中から「java.lang.Object」というのを選択します。これは、一番左端にあります。そして、このクラスを選択した状態で、「Classes」メニューから「Subclass java.lang.Object」を選びます。これで、java.lang.Objectの右側のカラムに「MyObject」というクラスが新たに作成されます。(ただし、この状態ではまだクラスのファイルは作成されていません)

Objectのサブクラス作成


3.作成したMyObjectクラスを選択した状態で、Infoウィンドウ「Attributes」を見てみましょう。そこで、使用言語やクラス名の設定が行なえることがわかります。とりあえず「MyObject」のままにしておきましょう。言語は、もちろん「Java」を選んでおきます。ここでObjective-CとJavaのどちらを選ぶかによって、どちらの言語によるクラスかが決まるのです。

4.その下には「0 Outlets」「0 Actions」という2つのタブが見えます。これが、Javaクラス作成のポイントです。これらは、それぞれ「Javaクラス内でCocoaコントロールを利用する際のフィールド」「アクションイベントから呼び出すメソッド」を示します。フィールドっていうのは、クラスで使う変数のことです。ほら、クラス内のすべてのメソッドで利用するグローバルな変数とかを使う時、クラス定義のすぐ後に「Button b1;」なんて変数の宣言を書きますね? あれがフィールドです。つまり、CocoaのコントロールをJavaのフィールドの形でクラスに用意しておこう、というわけです。

5.では、まずOutlet(アウトレット)を作りましょう。InfoウィンドウのAttributesで、「0 Outlets」タブをクリックして選択します。そして、下にある「Add」ボタンを押して下さい。これで「myOutlet」という項目が新たに作成されます。そのまま、名前を「text1」と変更しておきましょう。そして、右側の「Type」という項目の右端にある三角マークをクリックし、現れた一覧リストから「NSTextField」を選んでおきます。(註:ただし、Mac OS X 10.2以前だと、バージョンによってうまくリストが選択できない場合があるみたいです。この場合は、idのままにしておいて下さい)

Outletの作成


6.次に、Action(アクション)の作成です。同様に「0 Actions」タブをクリックして表示を切り替え、「Add」ボタンを押します。これで「myAction()」という項目が作成されます。そのまま、名前を「btn1Click()」と修正しておきましょう。最後の()は書かなくても自動的につけてくれます。

7.これでクラスの設定は完了です。Nibファイルウィンドウの「Classes」タブで、「MyObject」を選択し、「Classes」メニューから「Create Files for MyObject」を選んで下さい。これでファイルの保存ダイアログが現れます。ここでは、普通のセーブパネル以外に「Create files」「Insert into targets」というのが表示されます。前者は、「どのクラスのファイルを作成するか」で、後者は「プロジェクトのターゲット(設定みたいなもの)にファイルを追加するか」を示すものです。これらは、初期状態のまま何も変更しないで下さい。そのまま「Choose」ボタンを押して保存すればファイルが作成されます。

 これでMyObjectというクラスが作成されました。単にクラスを作るだけでなく、「アウトレット」と「アクション」というものを設定しなければいけないのがCocoa-Javaの特徴です。また、AttributesでJavaとObjective-Cを選択するようになってますから、間違って他の言語を選んでしまうと「なんじゃこのソースコードは?」と絶句することになります。これらの点によく注意しておきましょう。


■インスタンスの作成と接続

 さて、これで一応クラスはできたのですが、このままでは何も機能しません。なぜなら、作成したアウトレットとアクションに何の設定もされていないからです。これらに「このアウトレットはこの部品を示すんですよ」「このアクションは、この部品のこのメソッドを呼び出しますよ」ということを教えてやらないといけないんです。——が、そのためには、クラスの状態のままではダメです。インスタンスを作ってやらないといけないのです。ほら、Javaではクラスは「インスタンスを作って操作する」のが基本でしたね? Cocoa-Javaの場合も同じです。

 インスタンスの作り方は簡単です。Nibファイルウィンドウで「Classes」タブを選び、MyObjectを選択して下さい。そして「Classes」メニューから、「Instantiate MyObject」を選ぶとインスタンスが作成されます。

 作成されると、Nibファイルウィンドウの「Instances」タブに「MyObject」というアイコンが追加されます。これが、作成されたインスタンスです。そう、この「Instances」タブにある「MainMenu」とか「Window」とかいったものは、アプリケーション起動時に作成されるインスタンスだったんですね。

 インスタンスが作成できたら、アウトレットとアクションの設定をしましょう。これは「接続」と呼ばれる作業で行ないます。接続とは、クラス内のアウトレットやアクションと実際のコントロールの要素を結び付ける作業です。——では、さっそくやってみましょう。

1.まず、ウィンドウに配置したNSTextFieldと「text1」アウトレットを接続しましょう。——まず、Ctrlキーを押した状態でNibファイルウィンドウの「Instances」タブ内にある「MyObject」アイコンから、デザインウィンドウのNSTextFieldまでドラッグ&ドロップして下さい。NSTextFieldからビヨーンと線が延びます。

2.NSTextFieldの上まで線が延びたら、そのまま離します。するとInfoウィンドウが「Connections」に自動的に切り替わります。

3.そのまま、「Outlets」という部分にある「text1」を選択し、「Connect」ボタンを押して下さい。これで、MyObjectのtext1とNSTextFieldが接続されました。


MyObjectのアウトレットを接続


4.同様に、アクションも接続しましょう。——今度は、デザインウィンドウのNSButtonからNibファイルウィンドウの「Instances」タブ内の「MyObject」アイコンまで、やはりCtrlキーを押したままドラッグ&ドロップします。そして、Infoウィンドウの「Connections」で、Outletsの「target」という項目内にある「btn1Click()」を選択して「Connect」ボタンをクリックします。これで、NSButtonのアクションとbtn1Clickがつながりました。

 このように、アウトレットは「用意してあるクラスから、それに関連づけるコントロールへ」接続し、アクションは「アクションの起こるコントロールから、用意してあるクラスへ」接続します。また、アウトレットはInfoウィンドウの「Connections」のOutletsというところにそのまま項目が表示されますが、アクションの場合は「target」という項目の中に表示されます。この2点だけしっかり頭に入れておけば、接続自体はそう難しいことではありません。


■ソースコードを完成させる

 では、Interface Builderでファイルを保存したら、Project Builderに戻りましょう。そして、作成したMyObject.javaがどうなっているか見てください。ざっと、以下のようなコードが既に作成されているはずです。

/* MyObject */

import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;

public class MyObject {

public NSTextField text1; /* IBOutlet */

public void btn1Click(Object sender) { /* IBAction */
}

}


 中には、「public NSTextField text1;」という行が、単に「Object text1;」というようになっている人もいるかも知れません。これは、Interface Builderでアウトレットを作成する際、「text1」の種類として「NSTextField」を選択していなかったためでしょう。もし、そのような人は、この行を上のリストを参考にして書き換えて下さい。アウトレットで設定しなくとも、ソースコードを手作業で書き換えればちゃんとアウトレットは認識しますから。「Object text1;」のままにはしておかないで下さい。

 見ればわかるように、アウトレットのtext1は、MyObjectではクラスの変数(フィールドってやつ)として用意されていることがわかります。また、アクションとして用意したbtn1Clickは、「btn1Click」という名前のメソッドとして用意されています。

 この他、気づいた点としては、見なれない2つのライブラリがimportされていることでしょう。これらは、Cocoaの機能をJavaで利用するのに用意されているものです。従って、Cocoa-Javaの場合は「必ずこの2つをimportする」と考えておきましょう。

 では、btn1Clickメソッドを修正して、ボタンをクリックしたら何かを実行するようにしてみます。

public void btn1Click(Object sender) { /* IBAction */
String str1 = text1.stringValue();
str1 = "Hello, " + str1 + " !";
NSAlertPanel.runAlert(str1,"",null,null,null);
}


 ざっとこんな感じになります。btn1Clickメソッドをこのように修正したら、ビルド&実行しましょう。これは、Project Builderのブラウザウィンドウ左上にあるボタンを使って行なえます。ここにある「カナヅチ」アイコンは、プロジェクトをビルド(要するにアプリケーションを作ること)するもの、「カナヅチの上にパソコンのモニタ」アイコンが、ビルドした後実行するものです。この「ビルド&実行」ボタンをクリックすれば、プロジェクトを元にアプリケーションを作成して後、その場で実行します。

 これは、簡単なメッセージ表示プログラムです。テキストフィールドに自分の名前を記入して「Click」ボタンを押してみて下さい。「Hello,○○!」というようにアラートメッセージが画面に表示されます。

プロジェクトの実行画面



■コントロールの値とアラート表示

 では、ソースコードを見てみましょう。今回のはとてもシンプルですが、コントロール利用の基本となる要素が入っています。——まず、メソッドの最初をよく見てみましょう。

public void btn1Click(Object sender) {

 こんな形で書かれていますね。パラメータとして「Object」が1つ渡されています。これは、イベントが発生したコントロールを示すものと考えて下さい。アクションによるイベントの呼び出しはどんなコントロールから行なわれるかわかりません。それでオブジェクトの基本となるObjectクラスのインスタンスとして渡されるわけですね。

 メソッドで最初に行なってるのは、NSTextFieldに書かれたテキストを取り出して変数に設定する作業です。この行がそれを行なっている部分です。

String str1 = text1.stringValue();

 この「stringValue」というメソッドが、NSTextFieldの値をStringとして返すものです。これは、実はNSTextFieldではなく、コントロール類の共通の親クラスである「NSControl」というクラスに用意されているもので、ほとんどのコントロールで共通して使えます。

 Cocoaのコントロールの値というのは、非常に面白い仕組みになっています。Javaでは、AWTのコンポーネント(TextFieldなど)の値を操作するときは「getText」といったメソッドでテキストを取り出し、その後で必要に応じて整数や実数にキャストして使います。が、Cocoaのコントロールの場合、コントロールのクラス内に「Stringとして値を取り出すメソッド」「整数として取り出すメソッド」「実数として取り出すメソッド」・・というようにメソッドが多数用意されていて、必要に応じて適切なメソッドを呼び出せば、そのタイプの値が得られるようになっています。

 用意されているメソッド類を整理すると、こんな感じになります。

●値を取り出すメソッド●
stringValue() :値をStringとして取り出す
intValue() :値をint値として取り出す
floatValue() :値をfloat値として取り出す
doubleValue() :値をdouble値として取り出す

●値を設定するメソッド●
setStringValue(《String》) :Stringの値を設定する
setIntValue(《int》) :int値を設定する
setFloatValue(《float》) :float値を設定する
setDoubleValue(《double》) :double値を設定する

 メソッド自体はそう難しいものではないのでわかるでしょう。これらのメソッドを見て、「なんか変な感じだな」と思った人も多いことと思います。それは、メソッドのネーミングルールが守られていない(?)からです。

 Javaでは、「値を取り出すときはget○○、設定するときはset○○」という名前のメソッドが用意されていました。ところが、Cocoaではそうではないのです。Cocoaの場合、設定するメソッドは「set○○」ですが、値を取り出すメソッドは単に「○○」となり、getはつきません。

 Cocoaは元来、Objective-Cを使って記述することを考えて考案されました。またそのほとんどは、十年以上前の「NextStep」というOSのフレームワークを踏襲して作られています。つまり、根本的な概念や考え方が、Javaとは異なっているのです。それをJavaから利用できるようにしたため、Javaの基本的な考え方とはかなり違った構成になってしまっています。そのために混乱してしまう人も多いようです。

 「JavaとCocoaは異なる概念の環境なのだ」ということを、よく頭に入れておいて下さい。確かにCocoaはJavaで利用できますが、その基本的な考え方そのものまでJava本来の形に揃えてあるわけではないのです。

 さて、その先に進みましょう。テキストを取り出したら、それをちょっと加工して、最後にアラートメッセージとして画面に表示していますね。

NSAlertPanel.runAlert(str1,"",null,null,null);

 この部分が、そのためのものです。これは「NSAlertPanel」というアラーとパネルに関するクラス内にある「runAlert」というメソッドを利用したものです。このメソッドは、簡単なテキストを画面に表示するのに重宝するものです。これは、以下のように5つのString型の引数を持っています。

NSAlertPanel.runAlert(《str1》,《str2》,《str3》,《str4》,《str5》);

 3つのボタン名は、特に必要なければnullにして省略できます。また、複数のボタンを表示させた時には、選択したボタンを示す値(int値)が返されます。

 とりあえず、ボタンなどを使った利用は脇に置いといて、ここでは「簡単にテキストを画面に表示するもの」としてだけ覚えておきましょう。最初の2つの引数でタイトルとメッセージを指定すれば、それが表示される。それだけ覚えておけば十分です。

 また、「NSAlertPanelってどういうものだ?」といったことも、現状では知っておく必要はありません。上のフォームをそのまま丸暗記してしまって下さい。


■数字を使った利用例

 さて、これら「コントロールの値をやり取りするメソッド」と「メッセージを表示するメソッド」の2つだけでもわかれば、ちょっとした計算などのプログラムは作れるようになってしまいます。——例えば、数字を使った例として、ありがちですが「0から入力した数字までの合計を求める」プログラムを作ってみましょう。


public void btn1Click(Object sender) { /* IBAction */
int n = text1.intValue();
int m = 0;
for (int i = 1;i<=n;i++)
m += i;
NSAlertPanel.runAlert(Integer.toString(m),"",null,null,null);
}

合計を求める


 ざっと、こんな感じになるでしょう。「intValue」で整数として値を取り出せば、あとは簡単ですね。Javaの場合、まずテキストとしてgetTextするため、その後で数字に変換し、エラーになったときの処理を用意し・・と面倒なことまで考えないといけません。

 それがCocoaではintValueで取り出せば、テキストでない値が書き込まれたときの処理なども考えなくて済みます(この場合、0として得られます)。そういう点では、慣れればCocoaの方が使いやすいことでしょう。とりあえず、ここであげた値をやり取りするメソッドとrunAlertを使って、それぞれで応用したプログラムを考えてみるとよいでしょう。Cocoa-Javaの開発がどんなものか、少しずつイメージできるはずですから。

 

GO NEXT


GO HOME