広告 |
---|
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ 2010年01月06日 Java総合講座 - 初心者から達人へのパスポート 2009年11月開講コース 008号 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:毎週日曜の夜に発行 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:毎週水曜の夜に発行 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (2009年11月開講コース)008号 (当記事はvol.008のリバイバル(revival)版です。) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ======================================================== ◆ 01.ウィンドウの表示 ======================================================== 今回は、簡単なウインドウのアプリケーションを作ってみましょう。 ウインドウを使って、HumanTheaterで行っていたのと同じように Humanオブジェクトの名前を表示するアプリケーションを作ってみる ことにします。 Javaではウインドウ、メニュー、ボタンなどのいわゆるGUI (Graphical User Interface)の部品群もあらかじめ提供されて います。 その部品群のひとつがAWTです。 AWTは、Abstract Windowing Toolkitの略で、複数の(異種の)OS の持つGUIの共通部分を抽出して作ったクラス群です。 このおかげで、たとえばWindowsでもUnixのXウインドウ・システムでも 同じように動作するウインドウ・アプリケーションを作ることができます。 しかし、異なるOS間のGUIの共通部分を抽出したのでは、部品数が少なく て表現力に乏しいなどの欠点がありますので、現在では、Swingと呼ばれる、 もっと豊富な部品群が別途提供されています。 AWTがOSのGUI機能に依存しているのに対し、SwingはOSに依存せずに Javaで独自にGUIの部品群を作っていますので、OSに依存せずに表現力 豊かなウインドウのアプリケーションを作ることができます。 しかし、今回作るアプリケーションは説明を簡単に済ませるために、 AWTのほうを採用することにします。(Swingを使ったアプリケーショ ンの開発方法については、また後ほどお話いたします。) 通常のアプリケーションのウィンドウはフレーム・ウインドウ(frame window) と呼ばれるもので、AWTでもずばりFrameというクラスによって提供されます。 これはパッケージjava.awtに入っています。 しかし、単純にFrameをそのまま使うのではなく、何らかの拡張を行って使う ために、Frameのサブクラスを作って使います。 ここでは、HumanTheaterクラスと同じことをするFrameということで、Frameの サブクラスの名前をずばりHumanTheaterFrameにしようかとも思ったのですが、 長いのでやめにして、HumanFrameという名前にします。 さてHumanFrameのオブジェクトに以下のような作業をやらせたいと思います。 (1)タイトル・バーにHuman Theaterと表示させる。 (2)ウインドウのサイズを縦100ピクセル、横300ピクセルにする。 (ピクセルとは、いわゆる画素のことで、画像の最小単位です。) プログラム上の記述方法はいくつかありますが、たとえば、以下のような方法があります。 HumanFrame frame = new HumanFrame(); // HumanFrameのインスタンスを生成 frame.setTitle("Human Theater"); // タイトル・バーのタイトルを設定 frame.setSize(300, 100); // ウインドウのサイズを横300ピクセル、縦100ピクセルにする さて、HumanTheaterクラスと同じ様に、HumanFrameにも、「What is your name?」 「My name is Hanako.」という会話を表示させたいので、文字列を表示させるため のGUIの部品を追加しましょう。 その一つが、Labelというクラスです。 「What is your name?」用に一つと「My name is Hanako.」用に一つ、合計二つ のLabelオブジェクトを用意することにします。 Label label1 = new Label(); Label label2 = new Label(); 以上でLabelのインスタンスを2つ生成し、それぞれlabel1とlabel2という変数 に代入しました。 これらをHumanFrameのインスタンスに追加しましょう。ウインドウの上にGUI部品 を追加するにはadd( )というメソッドを使います。 クライアント領域とよばれる、ウインドウのお腹の部分にGUI部品を貼り付ける ことになりますが、この部分には、LayoutManager(レイアウト管理者)と呼ば れるオブジェクトを張り付けて、レイアウトを管理させることになっています。 そして、デフォルト(標準)ではBorderLayoutというLayoutManagerが張り付い ています。 ┌補足─────────────────────────┐ 詳しくいうと、LayoutManagerはインターフェイス(interface)と 呼ばれるもので、メソッドの名前など、呼び出し方(シグニチャー (signature)という)を規定したものです。詳しくは後述します。 一方、BorderLayoutはそのメソッドなどを実際にプログラミングし たクラスになっています。この「実際にプログラミングすること」 を「実装」(implement)といいます。 └───────────────────────────┘ BorderLayoutというLayoutManagerは、GUI部品を上・下・左・右・中央の合計 5個所に貼り付けられるようにします。 そのうち、上はNORTH、下はSOUTH、左はWEST、右はEAST、中央はCENTERと呼び ます。 では、label1をNORTHに、label2をSOUTHに配置させることにしましょう。 そのためには、add( )メソッドの呼び出しを次のように書きます。 frame.add(label1, BorderLayout.NORTH); frame.add(label2, BorderLayout.SOUTH); NORTHやSOUTHは、実際にはBorderLayoutクラスのstatic変数として定義されて いますので、上記のような指定の仕方になります。 次にHumanオブジェクトを生成して、これまでのように名前を答えさせましょう。 ただし、「What is your name?」「My name is Hanako.」という会話文は System.out.println( )を使って標準出力に表示するのではなく、Labelのインス タンスに表示させますので、LabelのsetText( )というメソッドを使って会話文を 入力しておきます。 Human human = new Human(1970, 8, 1); human.setName("Hanako"); label1.setText("What is your name?"); label2.setText("My name is " + human.getName() + "."); 最後の2行のようにそれぞれのLabelオブジェクトのsetText( )メソッドで文字列 を設定しておくと、Labelオブジェクトがそれを表示してくれます。 準備がととのったら、ウィンドウ全体を表示します。 frame.setVisible(true); ここでsetVisible( )は可視性を設定するメソッドで、true(真)を設定すると 可視状態になり、false(偽)を設定すると不可視状態になります。 可視状態にするということは、要するに表示することを意味します。 ところで、我々がウインドウを操作するときには、メニューを選択したり、ボタン をクリックするなどの事象が発生しますが、この「事象」のことを英語でevent (イベント)といいます。 現在のJavaでは、こういった事象(イベント)をEventListener(イベント・リスナー) というオブジェクトを通して、特定のオブジェクトのメソッド呼び出しに変換する仕組み が提供されています。 これは、一種のデザイン・パターンと呼ばれる技術に基づく、オブジェクト指向的な 仕組みなのですが、詳しいことは後述します。 イベント・リスナーというと事象の聞き手というような意味になりますが、事象を聞く という表現はちょっとへんですから、事象の監視者という意味だと理解しておいたほう がわかりやすいかもしれません。 今回は、「閉じる」ボタンをクリックした時のイベントの処理について説明します。 ウインドウを閉じるときの処理はとても大切なことです。 たとえば文書を編集しているときに誤って「閉じる」ボタンをクリックしてしまったら、 文書が保存もされずにアプリケーションが終了してしまった、なんてことになると困り ますね。 何も言わずに勝手にウインドウが閉じてしまっては困ります。 そこで、Javaでも、「閉じる」ボタンをクリックしたら勝手にウインドウを閉じるなん てことはしません。 「閉じる」ボタンをクリックしたら何をするか、ということは自分でプログラミングし ないといけないことになっているのです。 これらをふまえて記述したHumanFrameのソース・コードの例を下に記します。 ---------------------------------------------- package jp.co.flsi.lecture.ui; // 1行目 import java.awt.BorderLayout; // 2行目 import java.awt.Frame; // 3行目 import java.awt.Label; // 4行目 import java.awt.event.WindowEvent; // 5行目 import java.awt.event.WindowListener; // 6行目 import jp.co.flsi.lecture.human.Human; // 7行目 public class HumanFrame extends Frame { // 8行目 HumanEventListener listener = new HumanEventListener(); // 9行目 class HumanEventListener implements WindowListener { // 10行目 public void windowActivated(WindowEvent e) {}; // 11行目 public void windowClosed(WindowEvent e) { // 12行目 System.exit(0); // 13行目 }; // 14行目 public void windowClosing(WindowEvent e) { // 15行目 Frame frame = (Frame)e.getSource(); // 16行目 frame.setVisible(false); // 17行目 frame.dispose(); // 18行目 }; // 19行目 public void windowDeactivated(WindowEvent e) {}; // 20行目 public void windowDeiconified(WindowEvent e) {}; // 21行目 public void windowIconified(WindowEvent e) {}; // 22行目 public void windowOpened(WindowEvent e) {}; // 23行目 }; // 24行目 public HumanFrame() { // 25行目 super(); // 26行目 addWindowListener(listener); // 27行目 } // 28行目 public static void main(String[] args) { // 29行目 HumanFrame frame = new HumanFrame(); // 30行目 frame.setTitle("Human Theater"); // 31行目 frame.setSize(300, 100); // 32行目 setSize(幅, 高さ) Label label1 = new Label(); // 33行目 Label label2 = new Label(); // 34行目 frame.add(label1, BorderLayout.NORTH); // 35行目 frame.add(label2, BorderLayout.SOUTH); // 36行目 Human human = new Human(1970, 8, 1); // 37行目 human.setName("Hanako"); // 38行目 label1.setText("What is your name?"); // 39行目 label2.setText("My name is " + human.getName() + "."); // 40行目 frame.setVisible(true); // 41行目 } // 42行目 } // 43行目 ---------------------------------------------- 1行目から順番に見ていきましょう。 package jp.co.flsi.lecture.ui; // 1行目 もうおなじみのpackage文です。 今回のクラスは、GUI(Graphical User Interface)のクラスということで、 User Interfaceの略のuiをパッケージ名の最後に付けることにし、 jp.co.flsi.lecture.uiという名前のパッケージにHumanFrameクラスを入れる ことにしました。 次に2行目から7行目まで import java.awt.BorderLayout; // 2行目 import java.awt.Frame; // 3行目 import java.awt.Label; // 4行目 import java.awt.event.WindowEvent; // 5行目 import java.awt.event.WindowListener; // 6行目 import jp.co.flsi.lecture.human.Human; // 7行目 ですが、これらは今回使用するクラスのimport文です。例によって、Eclipseの コンテンツ・アシスト機能で自動的に入力されますから、細かい説明は省略します。 ただ、一つだけ注意して欲しいことがあります。 今回もHumanクラスを使います(7行目参照)が、HumanFrameクラスとHumanクラス では、パッケージが異なります。つまり、HumanFrameクラスはjp.co.flsi.lecture.ui に入っているのに対し、Humanクラスはjp.co.flsi.lecture.humanに入っています。 このように他のパッケージのクラスを参照する場合にはそのクラスにpublic指定がなけ ればなりません。 つまり、Humanクラスの定義時に public class Human というように、class文にpublicの指定をしておかなければならないことになっています。 そして、通常は、特別な理由がない限り、classにはpublicを指定するのが普通です。 したがって、Humanのclass文をpublic指定に変えておきましょう。 Humanだけでなく、今後定義するクラスは特に断らない限りpublicを指定するものと します。 次に8行目 public class HumanFrame extends Frame { // 8行目 のextends Frameという記述は、以前にも説明したようにHumanFrameというクラスが Frameのサブクラスであることを宣言しています。 次の9行目 HumanEventListener listener = new HumanEventListener(); // 9行目 は、その後の10行目から24行目までに定義しているイベント・リスナーのクラス HumanEventListenerのインスタンスを生成してlistenerという変数に代入して いるものです。 10行目〜24行目はイベント・リスナー(EventListener)のクラス定義ですが、 HumanFrameのクラス定義の内部に組み込まれていることに注意してください。 こういうのをinner class(内部クラス)とかnested class(ネストされたクラス、 入れ子にされたクラス)といいます。 (正確にいうと、nested classにはinner classでないものもあります。staticが 指定されたnested classがそれです。詳しいことは後述します。) HumanFrame専用のイベント・リスナーなのでHumanEventListenerという名前にしま したが、こういう場合はHumanFrameと別個に定義する必要がないので、HumanFrameの 内部に定義してしまうのが普通なのです。 このnested classの場合に注意して欲しいことは、クラス定義の最後(24行目)や その中のメソッドなどの定義の最後(11行目、14行目、19行目、20行目、21行目、 22行目、23行目)にも、文の終わりのマーク(;)を入れることです。 この点が普通のクラス定義と異なります。 10行目 class HumanEventListener implements WindowListener { // 10行目 のimplementsは実装するという意味のキーワードです。 その後ろのWindowListenerはウインドウ用のイベント・リスナーで、これもやはり インターフェイスと呼ばれるものです。 10行目の記述は、HumanEventListenerがWindowListenerというインターフェイス を実装したクラスであることを意味します。 そしてその実装の内容が11行目〜23行目です。 11行目 public void windowActivated(WindowEvent e) {}; // 11行目 のwindowActivated( )というメソッドは、ウインドウがアクティブになった (いわゆるフォーカスがあたった状態のことで、この状態だとタイトル・バーが 青色になっている)時に呼び出されるものですが、ここでは何の処理もしていません。 なお、引数のWindowEvent型のオブジェクトは、発生したイベントの情報を持つオブ ジェクトです。 12行目〜14行目 public void windowClosed(WindowEvent e) { // 12行目 System.exit(0); // 13行目 }; // 14行目 のwindowClosed( )というメソッドは、ウインドウが閉じたあとで呼び出される メソッドで、13行目のSystem.exit( )は、JVM(Java Virtual Machine)を終了 させる操作を示します。 このアプリケーションのウインドウが閉じてしまったら、もはやJVMが動いている必要は ありませんから、このような指示をしておきます。なお、exit( )の引数は、アプリケー ションが正常終了ならば0を指定します。 15行目〜19行目 public void windowClosing(WindowEvent e) { // 15行目 Frame frame = (Frame)e.getSource(); // 16行目 frame.setVisible(false); // 17行目 frame.dispose(); // 18行目 }; // 19行目 のwindowClosing( )というメソッドは「閉じる」ボタンをクリックしたときに呼び 出されますので、ここでウインドウを閉じる操作を行っておく必要があります。 16行目のe.getSource()は、イベントの発生元を取り出すためのメソッド呼び出しです。 その前についている(Frame)という記述は「キャスト」と言って、その後ろに指定した オブジェクトの型を変換することを指示するものです。 ここでは、e.getSource()が返してきたオブジェクトの型をFrameに変換しています。 このHumanEventListenerというイベント・リスナーはHumanFrameという(そのスー パークラスが)Frame型のオブジェクトにつないで使うことが予めわかっているので、 イベントの発生元もFrame型であることがわかっているわけです。それで、(Frame)という キャストによってFrame型に変換させるのです。 そして、そのイベントの発生元であるFrameオブジェクトをframeという変数に代入して います。 なお、16行目で宣言したframeという変数は、19行目の}で閉じられるブロック内でしか 通用しません。 一般に変数には適用できる範囲(scope)というものがあり、ブロック内で宣言された 変数はそのブロック内でしか通用しないことになっています。 もしそのブロックの外に同名の変数があった場合は、その変数は名前は同じでも、別の 変数として扱われます。 17行目では、このFrameオブジェクトを不可視の状態に変更しています。 そして18行目では、このFrameオブジェクトを消滅させています。こうすると、この Frameオブジェクトのために確保されていたメモリー上の記憶域も開放されます。 こうしてウインドウが閉じると先ほどの12行目〜14行目が実行され、JVMが終了させられ るわけです。 次の20行目〜23行目については説明を省略します。これらも何の処理もしていません。 public void windowDeactivated(WindowEvent e) {}; // 20行目 public void windowDeiconified(WindowEvent e) {}; // 21行目 public void windowIconified(WindowEvent e) {}; // 22行目 public void windowOpened(WindowEvent e) {}; // 23行目 次の25行目〜28行目 public HumanFrame() { // 25行目 super(); // 26行目 addWindowListener(listener); // 27行目 } // 28行目 はHumanFrameのコンストラクターの定義です。 26行目のsuper()というのは、スーパークラスのコンストラクターを呼び出すことを 意味します。 スーパークラス(ここではFrame)のコンストラクター(ここではFrame())がやって いたことはそのままスーパークラスのコンストラクターにやらせれば済む話なので、 このような呼び出しを行います。 27行目は、HumanFrameのオブジェクトにイベント・リスナーを登録するためのメソッド 呼び出しです。 ここでは、9行目で生成したイベント・リスナーのインスタンスを登録しています。 登録が何を意味するのか、知りたい人は、HumanFrameのインスタンスを HumanEventListenerのインスタンスと糸電話か電話線でつなぐようなイメージでも 頭に浮かべてください。 こうやってFrameのインスタンスにイベント・リスナーを登録しておくと、Frameオブ ジェクト上で(「閉じる」ボタンをクリックするなどの)イベントが発生したときに、 Frameオブジェクトがイベント・リスナーに(糸電話あるいは電話線を通して)イベント の情報を伝えてくれます。イベントの情報を伝えるというのは、具体的には11行目〜23 行目のメソッドを呼び出してくれるということです。 イベントの情報は、これらのメソッドの引数という形で渡され(伝えられ)ます。 次の29行目からは、main( )メソッドの定義です。30行目以降は先ほど説明したもの なので、もう説明する必要はないでしょう。 ただ、ちょっとわかりにくいところが一点ありますね。 30行目ではHumanFrameのインスタンスを生成していますが、このようにHumanFrameク ラスの定義の中でHumanFrameのインスタンスを生成するのは、頭をこんがらせる話かも しれません。 このようにJavaでは、クラス定義の中でそのクラスを使用する(いわゆる、再帰的に 使用する)ことは、許されているのですが、さらにmain( )メソッドがstaticメソッド (static指定のメソッド)であることに注目してください。 以前もお話したように、staticメソッドは、インスタンスとは関係しません。つまり、 インスタンスとは独立した存在なので、staticメソッドの中で同じクラスのインスタンス を生成したり、そのインスタンスにメッセージを送ったりすることには何も問題がないの です。 これを理解しやすくするためには、「クラスによって表現されるオブジェクトにはインス タンス以外にもstatic変数とstaticメソッドで構成されるオブジェクトがあり、これは インスタンスのオブジェクトとは別物である」と考えてください。 以上でHumanFrameのソース・コードが理解できたことと思います。 それでは次回は、ここまでの内容をEclipseに入力してウインドウの表示を試してみましょう。 ================================================ ◆ 02.演習問題 ================================================ 上記のイベント・リスナーの登録 addWindowListener(listener); // 27行目 を、HumanFrameのコンストラクター以外の場所で行うように プログラムを変更してみてください。 ====================================================== ◆ 03.前回の演習問題の答 ====================================================== 1. たとえば、やはり会話風に表示することにして package jp.co.flsi.lecture.human; class HumanTheater { public static void main(String[] args) { Human hanako = new Human(1970, 8, 1); hanako.setName("Hanako"); System.out.println("What is your name?"); hanako.sayName(); System.out.println("How old are you?"); System.out.println("I am " + hanako.getAge() + " years old."); } } という感じのプログラムにしてみるのが一つの答ですね。 2. dataOfBirthと同じようなやり方にするのが一つの方法ですね。 ◆編集後記◆━━━━━━━━━━━━━━━━━━━━━━━━ ☆最後まで読んでくださってありがとうございます。 ☆次回は、HumanFrameを少し対話的なアプリケーションに変えて みようと思います。 お楽しみに。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: http://www.flsi.co.jp/Java_text/ ★このメールマガジンは 「まぐまぐ(http://www.mag2.com)」 を利用して発行しています。 ★バックナンバーは http://www.flsi.co.jp/Java_text/ にあります。 ★このメールマガジンの登録/解除は下記Webページでできます。 http://www.mag2.com/m/0000193915.html ★このメールマガジンへの質問は下記Webページにて受け付けて います。わからない所がありましたら、どしどしと質問をお寄 せください。 http://www.flsi.co.jp/Java_text/ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製 |