広告 |
---|
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ 2010年01月13日 Java総合講座 - 初心者から達人へのパスポート 2009年11月開講コース 009号 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:毎週日曜の夜に発行 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:毎週水曜の夜に発行 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (2009年11月開講コース)009号 (当記事はvol.009のリバイバル(revival)版です。) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ======================================================== ◆ 01.ウィンドウの表示(前回の続き) ======================================================== それでは、HumanFrameのソース・コードをEclipseに入力していきましょう。 (1) Eclipsseを起動してください。 (2) 先にHumanクラスをpublic指定にしておきましょう。 Human.javaを開き、 class Human { の行の前にpublicを書き加えて public class Human { にしましょう。その後、保管(Ctrl + S)しましょう。 (なお、HumanTheater.javaのファイルは使いませんので、こちらが開いた ままだったら、そのタブの×マークをクリックして閉じておきましょう。) (3) HumanFrameを入れる新しいパッケージを作りましょう。 「パッケージ・エクスプローラ」の中のJStudy1を選択(クリック)しておき、 メニュー・バーの「ファイル」→「新規」→「パッケージ」を選択し、 「ソース・フォルダー」にJStudy1/srcがはいっていることを確認し、「名前」に jp.co.flsi.lecture.ui を入力し、「完了」ボタンをクリックしましょう。 (4) HumanFrameを作成しましょう。 メニュー・バーの「ファイル」→「新規」→「クラス」を選択し、「ソース・ フォルダー」にJStudy1/src 「パッケージ」にjp.co.flsi.lecture.uiがはいって いることを確認(違っていたら修正)し、「名前」に HumanFrame と入力します。 「修飾子」はpublicが選択されたままにし(ここでpublicを選択しておくと、 先ほどHumanクラスにpublic指定したのと同じことが行われます)、「どのメソッ ド・スタブを作成しますか?」はpublic static void main(String[] args)に チェック・マークをいれて(クリックすればチェックマークが入る)おきます。 「スーパークラス」については、右側の「参照」ボタンをクリックし、「型を 選択してください」にFrameを入力すると、「一致する項目」に Frame - java.awt というのが表示されますので、それを選択して「OK」ボタンをクリックします。 そうすれば、「スーパークラス」にjava.awt.Frameが入力されていますので 確認してください(最初からこれを手で入力してもかまいません)。 最後に「完了」ボタンをクリックしましょう。 (5) 自動的に作成されたHumanFrame.javaのソース・コード ---------------------------------------------- package jp.co.flsi.lecture.ui; import java.awt.Frame; public class HumanFrame extends Frame { /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ } } ---------------------------------------------- に編集を加えて、前回の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行目 ---------------------------------------------- と同じになるようにしてください。なお、コメントは入力する必要はありませんし、 import文は、上記と同じ順番に並べる必要はありません。コンテンツ・アシストを 使って入力したときの順番のままにしておいてください。 編集が終わったら、保管しましょう。 public class HumanFrame extends Frame { // 8行目 の行の左側に警告のマーク(丸みがかった橙色の三角形の中に!がはいったマーク) が表示されます(HumanFrameの文字列にも橙色のアンダーラインが付きます)が、 これは無視してください。問題はありません。 とりあえずマークの上にマウス・ポインターを重ねると説明が出ますが、これを解説 するためには直列化(serialization)の話をしなければならないので、あと回しに します。(直列化は、オブジェクトを保管したり転送したりするための技術です。) ┌補足─────────────────────────┐ この警告のマークがうっとうしいと思う人は、橙色のアンダー ラインが引かれているHumanFrameという文字列を選択(あるいは その中にカーソルを入れる)し、Ctrl + 1キーを押し(Ctrlキー を押しながら同時に数字の1のキーを押し)ます。 すると、(問題解決のための)ポップアップ・メニューが出てき ますので、「デフォルト・シリアル・バージョンIDの追加」を 選択(クリックしてEnterキーを押す)して下さい。 そうすると、何やら自動的にコードが追加されますね。保管 (Ctrl + S)してみると、今度は警告のマークは出ませんね。 これが何を意味するのかは、もっと後でJavaの学習が十分に進ん だ時点で直列化(シリアライズ)のお話のときに一緒に説明いた します。 └───────────────────────────┘ もし、エラー(赤い×マーク)が表示された場合は、ソース・コードに間違いがないか よく確認&修正したのち、保管し直してください。 (6) HumanFrameを実行してみましょう。 例によって、メニュー・バーから「実行」→「実行」→「Javaアプリケーション」を 選択します。 「Human Theater」というタイトル・バーのウインドウが開いて、「What is your name?」 という文と「My name is Hanako.」という文が表示されていれば、成功です。 このウインドウの「閉じる」ボタン(×ボタン)をクリックして閉じてください。 ちゃんと閉じますね。もし閉じない場合は、イベント・リスナーがらみのソース・コードが どこか間違っているのですね。 閉じない場合は、とりあえずEclipseの下のほうにある「コンソール」タブをクリックし、 その右側に現れる赤い四角形のマークをクリックしましょう。これで閉じますね。 それからソース・コードをよく確認して修正し、保管&実行をやり直してください。 しかし、こんな単純なアプリケーションじゃ、面白くないですね。 通常のウインドウのアプリケーションでは、何かを入力するとウインドウに結果が返って くるというような「対話的な動き」をするものが普通ですね。 では、少し対話的なアプリケーションを作ってみましょう。 ======================================================== ◆ 02.対話的なウィンドウのアプリケーション ======================================================== Humanには氏名を答えるメソッドの他に年齢を答えるメソッドも持っていました。 そこで、ウインドウでHumanの生年月日と氏名を入力し、ボタンをクリックしたら、 Humanのインスタンスが生成され、そのインスタンスが自分の氏名と現在の年齢を 答える、というアプリケーションを作ってみましょう。 HumanFrameのソース・コードを書き換えて作ろうかとも思ったのですが、もったい ないですからHumanFrameはそのまま残しておき、別のクラスとして作成することに します。 その新しいクラスはHumanWindowという名前にします。 HumanWindowには文字列入力のために、新たにTextFieldというGUI部品を使います。 また、ボタンのGUI部品としてはButtonというクラスを使います。 前回紹介したLabelというクラスは文字列を表示することはできますが、文字列の入力 には使用できません(プログラムで文字列を設定することはできますが、画面から入力 することはできません)。 一方、TextFieldは、画面上で文字列を入力し、それをそのまま表示することのできる GUI部品です。 ボタンをクリックしたときのイベント(事象)をとらえるためのイベント・リスナーも 必要になりますが、この場合によく使われるものとしてActionListenerというイベント・ リスナーがあります。 このActionListenerを実装してボタンのインスタンスにつないでやると、ボタンがク リックされたときにActionListenerにイベントを通知してくれます。具体的には、 ActionListenerのactionPerformed( )というメソッドが呼び出される仕組みになって います。 したがって、このactionPerformed( )メソッドの中でHumanのインスタンスを生成して HumanWindowに入力された生年月日や氏名のデータの受け渡しをすればいいのです。 なお、ウインドウに貼り付けるGUI部品がある程度増えてきましたが、LayoutManager (レイアウト・マネジャー)の説明をするのが面倒なので、今回はLayoutManager無しで レイアウトを設定したいと思います。 それでは、HumanWindowを作ってみましょう。 下記は、これらの部品を使って作成したHumanWindowのソース・コードの例です。 ---------------------------------------------- package jp.co.flsi.lecture.ui; import java.awt.Button; import java.awt.Frame; import java.awt.Label; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import jp.co.flsi.lecture.human.Human; public class HumanWindow extends Frame { private HumanEventListener eventListener = new HumanEventListener(); private HumanActionListener actionListener = new HumanActionListener(); private Label labelDateOfBirth = new Label(); private Label labelYear = new Label(); private Label labelMonth = new Label(); private Label labelDay = new Label(); private Label labelName = new Label(); private Label labelResponse = new Label(); private Button instanceButton = new Button(); private TextField textFieldYear = new TextField(); private TextField textFieldMonth = new TextField(); private TextField textFieldDay = new TextField(); private TextField textFieldName = new TextField(); class HumanEventListener implements WindowListener { public void windowActivated(WindowEvent e) {}; public void windowClosed(WindowEvent e) { System.exit(0); }; public void windowClosing(WindowEvent e) { Frame frame = (Frame)e.getSource(); frame.setVisible(false); frame.dispose(); }; public void windowDeactivated(WindowEvent e) {}; public void windowDeiconified(WindowEvent e) {}; public void windowIconified(WindowEvent e) {}; public void windowOpened(WindowEvent e) {}; }; class HumanActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { Button button = (Button)e.getSource(); HumanWindow window = (HumanWindow)button.getParent(); int year = Integer.parseInt(window.getTextFieldYear().getText()); int month = Integer.parseInt(window.getTextFieldMonth().getText()); int day = Integer.parseInt(window.getTextFieldDay().getText()); Human human = new Human(year, month, day); human.setName(window.getTextFieldName().getText()); window.getLabelResponse().setText( "私は" + human.getName() + "です。" + human.getAge() + "歳です。"); }; }; public HumanWindow() { super(); setTitle("ヒュウマン劇場"); setSize(400, 150); setLayout(null); labelDateOfBirth.setBounds(10, 30, 200, 20); getTextFieldYear().setBounds(210, 30, 40, 20); labelYear.setBounds(255, 30, 20, 20); getTextFieldMonth().setBounds(290, 30, 20, 20); labelMonth.setBounds(315, 30, 20, 20); getTextFieldDay().setBounds(350, 30, 20, 20); labelDay.setBounds(375, 30, 20, 20); labelName.setBounds(10, 60, 60, 20); getTextFieldName().setBounds(70, 60, 320, 20); instanceButton.setBounds(120,90, 160, 20); getLabelResponse().setBounds(10, 120, 380, 20); add(labelDateOfBirth); add(getTextFieldYear()); add(labelYear); add(getTextFieldMonth()); add(labelMonth); add(getTextFieldDay()); add(labelDay); add(labelName); add(getTextFieldName()); add(instanceButton); add(getLabelResponse()); labelDateOfBirth.setText("生成するヒュウマンの生年月日:"); labelYear.setText("年"); labelMonth.setText("月"); labelDay.setText("日"); labelName.setText("氏名:"); instanceButton.setLabel("インスタンスの生成"); instanceButton.addActionListener(actionListener); addWindowListener(eventListener); setVisible(true); } public TextField getTextFieldYear() { return textFieldYear; } public TextField getTextFieldMonth() { return textFieldMonth; } public TextField getTextFieldDay() { return textFieldDay; } public TextField getTextFieldName() { return textFieldName; } public Label getLabelResponse() { return labelResponse; } public static void main(String[] args) { HumanWindow frame = new HumanWindow(); } } ---------------------------------------------- 次回は、このソース・コードの説明をしたあと、Eclipseに入力して実行してみます。 ================================================ ◆ 03.演習問題 ================================================ Eclipseの使い方に慣れてきた人は、HumanWindowを独力でEclipseに入力 して保管&実行(すなわち予習)してみてください。 ====================================================== ◆ 04.前回の演習問題の答 ====================================================== いきなりむずかしい問題を出してしまいました。 この問題は、まだ解けなくてもいいですし、むずかしいと感じた人は 無視してしまってけっこうです。 興味のある人だけ、以下を読んでください。 HumanFrameのコンストラクター以外の場所といったら、とりあえず main( )メソッドがありますから、main( )メソッドの中で27行目の コードを指定する方法を考えてみましょう。 main( )メソッドの中では、listenerという変数は、HumanFrameの インスタンスとは独立していなければいけません(なぜならmain( ) メソッドはstaticメソッドだから)から、listenerはHumanFrameの インスタンス変数であってはいけないことになります。 したがって、まず HumanEventListener listener = new HumanEventListener(); // 9行目 をmain( )メソッドの中に移動しましょう。これで、listenerが、 HumanFrameのインスタンス変数ではなくなります。 しかし、HumanEventListenerのクラスがHumanFrameの中にinner class として定義されているのでは、HumanFrameのインスタンスの中でしか使用 できません。したがって、main( )メソッドの中で9行目のコードを書くと エラーになってしまいます。 一つの解決方法はHumanEventListenerを外部のクラスにしてしまうことです。 そうすれば、main( )メソッドの中でHumanEventListenerのインスタンスを 生成(9行目)して、それをHumanFrameのインスタンスにつなぐ (addWindowListener(listener);を行う)ことができます。 そのソース・コードはたとえば以下のようになります。 -------------- 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 sun.security.action.GetLongAction; import jp.co.flsi.lecture.human.Human; // 7行目 public class HumanFrame extends Frame { // 8行目 public HumanFrame() { // 25行目 super(); // 26行目 } // 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行目 HumanEventListener listener = new HumanEventListener(); // 9行目 frame.addWindowListener(listener); // 27行目 } // 42行目 } // 43行目 -------------- 上記のように9行目を41行目の下に移動したとともに、さらにその下に 27行目を移動しました。 ただし、27行目のaddWindowListener( )メソッドは、main( )メソッド から見れば他人(HumanFrameのインスタンス)のメソッドなので、ここでは メソッド呼び出しの前にframe.というようにオブジェクトの指名が必要になり ます。 また、HumanEventListenerの定義部分(10行目〜24行目)はHumanFrameの ソース・コードから削除し、下記のように外部の(独立した)クラスとして 作成します。 -------------- package jp.co.flsi.lecture.ui; import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; public 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行目 -------------- もう一つ別の解決方法を紹介しましょう。それはnested classとしての HumanEventListenerのクラス定義にstatic指定をすることです。 たとえば -------------- 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行目 static 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行目 } // 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行目 HumanFrame.HumanEventListener listener = new HumanFrame.HumanEventListener(); // 9行目 frame.addWindowListener(listener); // 27行目 } // 42行目 } // 43行目 -------------- この10行目のようにclass文にstaticを指定するとHumanFrameのインスタンス とは独立するのでHumanEventListenerを外部のクラスにする必要がなくなりま す。 ただし、この場合、上記の9行目のように、HumanEventListenerの前に HumanFrame.をつけて参照する必要があります。 (9行目の文が長くなってしまったので、2行にわけています。) さらにもう一つ別の解決方法を紹介しましょう。 -------------- 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 java.awt.event.WindowAdapter; import jp.co.flsi.lecture.human.Human; // 7行目 public class HumanFrame extends Frame { // 8行目 public HumanFrame() { // 25行目 super(); // 26行目 } // 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行目 WindowListener listener = new WindowAdapter() { // <補足1> 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行目 }; // <補足2> frame.addWindowListener(listener); // 27行目 } // 42行目 } // 43行目 -------------- 上記の<補足1>から<補足2>までの行は、HumanEventListenerクラスの定義の 代わりにWindowAdapterというクラスを使った例です。 WindowAdapterは抽象クラスと言って、そのままではインスタンスが生成でき ないクラスなのですが、<補足1>から<補足2>までのようにしてメソッドの実装 を行うと、(いわゆる無名クラスと呼ばれるサブクラスを作ったことになり) インスタンス生成ができます。 HumanEventListenerクラスのようにWindowListenerを実装するのに比べて、 最小限必要なメソッドだけを実装すればすむので、コードが少なくてすみます。 (もともと、このようにWindowListenerの実装を簡単にすることを目的として 作られたのがWindowAdapterです。) ◆編集後記◆━━━━━━━━━━━━━━━━━━━━━━━━ ☆最後まで読んでくださってありがとうございます。 ☆次回は、HumanWindowをEclipseに入力して実行してみるとともに、 さらに拡張を加えていきます。 お楽しみに。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: 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. 不許無断複製 |