広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年02月17日

    Java総合講座 - 初心者から達人へのパスポート
                  2009年11月開講コース 014号

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:毎週日曜の夜に発行
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:毎週水曜の夜に発行
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(2009年11月開講コース)014号
 当記事はvol.014のリバイバル(revival)版です。
 vol.014の内容を最新のEclipse、Javaに基づいて書き直しています。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


========================================================
◆ 01.和暦を西暦に変換するクラス(続き)
========================================================

前回は遅延生成のお話をしましたが、CalendarConverterのインス
タンスを遅延生成するCalendarConverterWindowクラスのソース・
コードの全景を下に掲載しておきます。

前回の演習問題がうまくいかなかった人は、下のソース・コードと
照らし合わせて修正した後、再度実行して確認してみてください。

-------------------------------------------------------
package jp.co.flsi.lecture.ui;

import java.awt.Button;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
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.util.CalendarConverter;

public class CalendarConverterWindow extends Frame {
   private CalendarEventListener eventListener = new CalendarEventListener();
   private CalendarActionListener actionListener = new CalendarActionListener();
   private Label labelJaCalendar = new Label();
   private Panel ckboxPanel = new Panel();
   private CheckboxGroup nameOfEraCkboxGroup = new CheckboxGroup();
   private Checkbox checkboxMeiji =
      new Checkbox("明治", getNameOfEraCkboxGroup(), false);
   private Checkbox checkboxTaisho =
      new Checkbox("大正", getNameOfEraCkboxGroup(), false);
   private Checkbox checkboxShowa =
      new Checkbox("昭和", getNameOfEraCkboxGroup(), true);
   private Checkbox checkboxHeisei =
      new Checkbox("平成", getNameOfEraCkboxGroup(), false);
   private Label labelJaYear = new Label();
   private Label labelJaMonth = new Label();
   private Label labelJaDay = new Label();
   private Label labelGreCalendar = new Label();
   private Label labelGreYear = new Label();
   private Label labelGreMonth = new Label();
   private Label labelGreDay = new Label();
   private Button convertJa2GreButton = new Button();
   private Button convertGre2JaButton = new Button();
   private TextField textFieldJaYear = new TextField();
   private TextField textFieldJaMonth = new TextField();
   private TextField textFieldJaDay = new TextField();
   private TextField textFieldGreYear = new TextField();
   private TextField textFieldGreMonth = new TextField();
   private TextField textFieldGreDay = new TextField();
   private CalendarConverter calendarConverter = null;
  
   class CalendarEventListener 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 CalendarActionListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         Button button = (Button)e.getSource();
         CalendarConverterWindow window = (CalendarConverterWindow)button.getParent();
         CalendarConverter calendarConverter = window.getCalendarConverter();
         if (button.getLabel().equals("和暦から西暦へ変換")){
            if (window.getNameOfEraCkboxGroup().getSelectedCheckbox().getLabel().equals("明治")) calendarConverter.setJaNameOfEra(0);
            else if (window.getNameOfEraCkboxGroup().getSelectedCheckbox().getLabel().equals("大正")) calendarConverter.setJaNameOfEra(1);
            else if (window.getNameOfEraCkboxGroup().getSelectedCheckbox().getLabel().equals("昭和")) calendarConverter.setJaNameOfEra(2);
            else if (window.getNameOfEraCkboxGroup().getSelectedCheckbox().getLabel().equals("平成")) calendarConverter.setJaNameOfEra(3);
            calendarConverter.setJaYear(Integer.parseInt(window.getTextFieldJaYear().getText()));
            calendarConverter.setMonth(Integer.parseInt(window.getTextFieldJaMonth().getText()));
            calendarConverter.setDay(Integer.parseInt(window.getTextFieldJaDay().getText()));
            calendarConverter.convertJaCal2GreCal();
            window.getTextFieldGreYear().setText(Integer.toString(calendarConverter.getGreYear()));
            window.getTextFieldGreMonth().setText(Integer.toString(calendarConverter.getMonth()));
            window.getTextFieldGreDay().setText(Integer.toString(calendarConverter.getDay()));
         }
         else {
            calendarConverter.setGreYear(Integer.parseInt(window.getTextFieldGreYear().getText()));
            calendarConverter.setMonth(Integer.parseInt(window.getTextFieldGreMonth().getText()));
            calendarConverter.setDay(Integer.parseInt(window.getTextFieldGreDay().getText()));
            calendarConverter.convertGreCal2JaCal();
            if (calendarConverter.getJaNameOfEra() == 0) window.getNameOfEraCkboxGroup().setSelectedCheckbox(window.checkboxMeiji) ;
            else if (calendarConverter.getJaNameOfEra() == 1) window.getNameOfEraCkboxGroup().setSelectedCheckbox(window.checkboxTaisho) ;
            else if (calendarConverter.getJaNameOfEra() == 2) window.getNameOfEraCkboxGroup().setSelectedCheckbox(window.checkboxShowa) ;
            else if (calendarConverter.getJaNameOfEra() == 3) window.getNameOfEraCkboxGroup().setSelectedCheckbox(window.checkboxHeisei) ;
            window.getTextFieldJaYear().setText(Integer.toString(calendarConverter.getJaYear()));
            window.getTextFieldJaMonth().setText(Integer.toString(calendarConverter.getMonth()));
            window.getTextFieldJaDay().setText(Integer.toString(calendarConverter.getDay()));
         }
      };
   };
  
   public CalendarConverterWindow()  {
      super();
      setTitle("和暦西暦変換");
      setSize(400, 150);
      setLayout(null);
      labelJaCalendar.setBounds(10, 30, 200, 20);
      ckboxPanel.setLayout(new GridLayout(1,4));
      ckboxPanel.add(checkboxMeiji);
      ckboxPanel.add(checkboxTaisho);
      ckboxPanel.add(checkboxShowa);
      ckboxPanel.add(checkboxHeisei);
      ckboxPanel.setBounds(45, 60, 180, 20);
      getTextFieldJaYear().setBounds(230, 60, 20, 20);
      labelJaYear.setBounds(255, 60, 20, 20);
      getTextFieldJaMonth().setBounds(290, 60, 20, 20);
      labelJaMonth.setBounds(315, 60, 20, 20);
      getTextFieldJaDay().setBounds(350, 60, 20, 20);
      labelJaDay.setBounds(375, 60, 20, 20);
      convertJa2GreButton.setBounds(220,90, 160, 20);
      convertGre2JaButton.setBounds(20,90, 160, 20);
      labelGreCalendar.setBounds(10, 120, 200, 20);
      getTextFieldGreYear().setBounds(210, 120, 40, 20);
      labelGreYear.setBounds(255, 120, 20, 20);
      getTextFieldGreMonth().setBounds(290, 120, 20, 20);
      labelGreMonth.setBounds(315, 120, 20, 20);
      getTextFieldGreDay().setBounds(350, 120, 20, 20);
      labelGreDay.setBounds(375, 120, 20, 20);
      add(labelJaCalendar);
      add(ckboxPanel);
      add(getTextFieldJaYear());
      add(labelJaYear);
      add(getTextFieldJaMonth());
      add(labelJaMonth);
      add(getTextFieldJaDay());
      add(labelJaDay);
      add(convertJa2GreButton);
      add(convertGre2JaButton);
      add(labelGreCalendar);
      add(getTextFieldGreYear());
      add(labelGreYear);
      add(getTextFieldGreMonth());
      add(labelGreMonth);
      add(getTextFieldGreDay());
      add(labelGreDay);
      labelJaCalendar.setText("和暦:");
      labelJaYear.setText("年");
      labelJaMonth.setText("月");
      labelJaDay.setText("日");
      convertJa2GreButton.setLabel("和暦から西暦へ変換");
      convertGre2JaButton.setLabel("西暦から和暦へ変換");
      labelGreCalendar.setText("西暦:");
      labelGreYear.setText("年");
      labelGreMonth.setText("月");
      labelGreDay.setText("日");
      convertJa2GreButton.addActionListener(actionListener);
      convertGre2JaButton.addActionListener(actionListener);
      addWindowListener(eventListener);
      setVisible(true);
   }

   public CheckboxGroup getNameOfEraCkboxGroup() {
      return nameOfEraCkboxGroup;
   }

   public TextField getTextFieldJaYear() {
      return textFieldJaYear;
   }

   public TextField getTextFieldJaMonth() {
      return textFieldJaMonth;
   }

   public TextField getTextFieldJaDay() {
      return textFieldJaDay;
   }

   public TextField getTextFieldGreYear() {
      return textFieldGreYear;
   }

   public TextField getTextFieldGreMonth() {
      return textFieldGreMonth;
   }

   public TextField getTextFieldGreDay() {
      return textFieldGreDay;
   }

   public CalendarConverter getCalendarConverter( ) {
      if (calendarConverter == null) calendarConverter = new CalendarConverter();
      return calendarConverter;
   }
  
   public static void main(String[] args) {
      CalendarConverterWindow frame = new CalendarConverterWindow();
   }

}
-------------------------------------------------------


それでは、遅延生成を使いながら、和暦から年齢計算をできるように
HumanWindowを拡張していきましょう。

CalendarConverterを遅延生成させるやり方は理解していることと思い
ますので、今度はHumanWindowの中でHumanを遅延生成させる方法を考えて
みてください。

以下の点に気がつきますね。

Humanクラスはコンストラクターによって生年月日を設定しており、イン
スタンスが生成された後は、生年月日の変更ができないようになっていま
す。
これでは、別の生年月日を設定したいときにはインスタンスを生成し直さ
なければならなくなります。

つまり、一度生成したインスタンスをずっと使い続けることができないの
です。したがって、このままでは遅延生成のやり方が有効ではないのです。

遅延生成を有効にするためには、生年月日をsetメソッドで設定/変更でき
るようにしておく必要があります。

今後のアプリケーションで使用することを考慮して、Humanをコピーして別の
HumanInfoというクラスを作り、生年月日のsetメソッドを組み込むことにし
ます。

というわけで、HumanをコピーしてHumanInfoを作ってみましょう。

(1) Eclipseを起動して「パッケージ・エクスプローラー」からJStudy1→src→
jp.co.flsi.lecture.human→Human.javaと展開し、Human.javaを右クリック→
「コピー」を選択し、jp.co.flsi.lecture.humanを右クリック→「貼り付け」
を選択します。

(2) 「名前の競合」ウインドウが開いて、新規名(コピー先の名前)を聞いて
きますので、
HumanInfo
を入力して「OK」ボタンをクリックします。

jp.co.flsi.lecture.humanの下にHumanInfo.javaができますので、それをダブル・
クリックして開きましょう。

ソース・コードが(クラス名以外は)Humanと同じになっているはずです。それに
修正を加えて以下のように書き換えましょう。

-------------------------------------------------------
package jp.co.flsi.lecture.human;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class HumanInfo {
   private String name;
   private GregorianCalendar dateOfBirth;
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
   public void setDateOfBirth(int birthYear, int birthMonth, int birthDate) {
      dateOfBirth = new GregorianCalendar(birthYear, birthMonth -1, birthDate);
   }
   public int getAge() {
      GregorianCalendar today = new GregorianCalendar();
      if (today.get(Calendar.MONTH) > dateOfBirth.get(Calendar.MONTH)) return today.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR);
      if (today.get(Calendar.MONTH) == dateOfBirth.get(Calendar.MONTH)) {
         if (today.get(Calendar.DAY_OF_MONTH) >= dateOfBirth.get(Calendar.DAY_OF_MONTH))
            return today.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR);
      }
      return today.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR) - 1;
   }
}
-------------------------------------------------------

修正点は以下の通りです。

・フィールドdateOfBirthの変数宣言の文からfinal指定を取り除きました。
・コンストラクターとsayName( )メソッドを削除し、コンストラクターの代わりに
フィールドdateOfBirthのsetメソッドsetDateOfBirth( )を用意しました。
(sayName( )メソッドの削除は、今回の話題とは関係ありませんが、今後使用する
予定がないため削除しました。)


それでは、HumanWindowを拡張していきたいのですが、現時点のHumanWindow自身は
記念に残す(何の記念だかわかりませんが)ことにして、HumanWindowのコピーを
HumanInfoWindowという名前でjp.co.flsi.lecture.ui下に作成(先ほどHumanInfo
を作成したときと同じ方法でコピーして作成)しましょう。

そのソース・コードを一部修正して以下のようにします。

-------------------------------------------------------
package jp.co.flsi.lecture.ui;

import java.awt.Button;
import java.awt.Choice;
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.HumanInfo;
import jp.co.flsi.lecture.util.CalendarConverter;

public class HumanInfoWindow extends Frame {
   private HumanEventListener eventListener = new HumanEventListener();
   private HumanActionListener actionListener = new HumanActionListener();
   private Label labelDateOfBirth = new Label();
   private Choice nengoChoice = new Choice();
   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();
   private HumanInfo humanInfo = null;
   private CalendarConverter calendarConverter = null;
  
   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();
         HumanInfoWindow window = (HumanInfoWindow)button.getParent();
         int nengoIndex = nengoChoice.getSelectedIndex();
         int year = Integer.parseInt(window.getTextFieldYear().getText());
         int month = Integer.parseInt(window.getTextFieldMonth().getText());
         int day = Integer.parseInt(window.getTextFieldDay().getText());
         HumanInfo human = window.getHumanInfo();
         CalendarConverter calendarConverter = window.getCalendarConverter();
         if (nengoIndex < 4) {
            calendarConverter.setJaNameOfEra(nengoIndex);
            calendarConverter.setJaYear(year);
            calendarConverter.convertJaCal2GreCal();
            year = calendarConverter.getGreYear();
         }
         human.setDateOfBirth(year, month, day);
         human.setName(window.getTextFieldName().getText());
         window.getLabelResponse().setText("私は" + human.getName() + "です。" + human.getAge() + "歳です。");
      };
   };
  
   public HumanInfoWindow()  {
      super();
      setTitle("ヒュウマン劇場");
      setSize(400, 150);
      setLayout(null);
      labelDateOfBirth.setBounds(10, 30, 80, 20);
      nengoChoice.setBounds(120, 30, 80, 20);
      nengoChoice.add("明治");
      nengoChoice.add("大正");
      nengoChoice.add("昭和");
      nengoChoice.add("平成");
      nengoChoice.add("西暦");
      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(nengoChoice);
      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 HumanInfo getHumanInfo( ) {
      if (humanInfo == null) humanInfo = new HumanInfo();
      return humanInfo;
   }
  
   public CalendarConverter getCalendarConverter( ) {
      if (calendarConverter == null) calendarConverter = new CalendarConverter();
      return calendarConverter;
   }
  
   public static void main(String[] args) {
      HumanInfoWindow frame = new HumanInfoWindow();
   }

}
-------------------------------------------------------

ここで、Choiceという新しいGUI部品がでてきましたので、説明しておきます。

Choiceは通常、何らかの文字列がはいったテキスト・フィールドの右側に逆三角形
のボタンがついた形をしています。

そして、その逆三角形のボタンをクリックすると、その下に文字列のリストが開き
ます。

今回のソース・コードで説明すると、19行目

   private Choice nengoChoice = new Choice();

では、Choiceのインスタンスを生成してnengoChoiceというフィールドに代入し、77行目

      nengoChoice.setBounds(120, 30, 80, 20);

でウインドウ上の配置を決め、78行目

      nengoChoice.add("明治");

で、Choiceのリストの1行目に「明治」という文字列を入れ、さらに79〜82行目

      nengoChoice.add("大正");
      nengoChoice.add("昭和");
      nengoChoice.add("平成");
      nengoChoice.add("西暦");

で、リストの2行目から5行目にかけて、それぞれ「大正」「昭和」「平成」「西暦」
という文字列を入れています。

つまりChoiceのリストには、add( )メソッドを実行した順番に応じて上の行から下の
行へと文字列がはいっていきます。
そして94行目

       add(nengoChoice);

で、ウインドウにこのChoiceというGUI部品を貼り付けています。

このChoiceのリストを開いて、そのうちの一つの行をクリックすると、その行が
選択されたことになり、リストを閉じた後、その選択された行が表示されること
になります。

この選択された行が何行目か知りたいときは、ChoiceクラスのgetSelectedIndex( )
というメソッドを使用します。
これを使用しているのが53行目

        int nengoIndex = nengoChoice.getSelectedIndex();

です。

getSelectedIndex( )メソッドはリスト上で選択された行のインデックスを返します。
ここでインデックス(getSelectedIndexのIndex)というのは項目の番号(ここでは
リストの何行目かを示す番号)で、1行目が0、2行目が1、あと順番にそれぞれ2, 3,
4,・・・という番号がついています。

53行目を実行するとこのインデックスの値がnengoIndexという変数に代入されること
になります。


今回のソース・コードでは、明治がインデックス0、大正がインデックス1、昭和が
インデックス2、平成がインデックス3となりますので、ちょうどCalendarConverter
のjaNameOfEraの値と一致します(というより、わざとそのように合わせたのです)。


では、今回はここまでにします。



================================================
◆ 02.演習問題
================================================

上記のソース・コードを、実際にEclipseに入力して、実行しなさい。

また、以前のHumanWindowクラスからどのように修正が加えられたのか、
また何のためにそのような修正を行ったのか考えなさい。



======================================================
◆ 03.前回の演習問題の答
======================================================

今回の本文を参照してください。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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. 不許無断複製