広告 |
---|
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ 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. 不許無断複製 |