広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年03月10日

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

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


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


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


========================================================
◆ 01.ファイルへの入出力とメニュー・バー
========================================================

今回は、ファイルへの入出力のお話をします。

ファイルへ入出力するためのクラスが既にJavaのAPIの中にいろ
いろと用意されていますが、今回はそのうち最も簡単でかつ効率
がよいと考えられる、次のクラスを使用することにします。

入力するためのクラス: BufferedReader
出力するためのクラス: BufferedWriter

なお、これらのクラスだけではファイルのオープン(ファイルを
開くこと)ができないため、それぞれFileReaderとFileWriterと
いうクラスを使ってファイルをオープンします。

使い方を簡単に説明しておきましょう。


まず、ファイルへの出力を行うためには、

// c:\abc\efgというフォルダーにあるfile1.txtというファイル名のファイルを開く
FileWriter aFileWriter = new FileWriter("c:\abc\efg\file1.txt", false);
/* 上記の2番目の引数のfalseは、既にファイルにデータが入っているときに
   追記(append)ではなく最初から書き換えることを意味する。
   代わりにtrueを指定した場合は追記となり、既に入っているデータの後ろに
   新しいデータが書き足されることになる。                  */

// そのファイル用にBufferedWriterのインスタンスを生成する
BufferedWriter out = new BufferedWriter(aFileWriter);

// そのファイルに文字列を書き出す。
out.write("文字列");

// 改行する。
out.newLine();

// このout.write()とout.newLine()を繰り返してデータを何行か書き出す。

// 最後に、そのファイルを閉じる。
out.close();

という感じでBufferedWriterを使います。


また、ファイルからの入力を行うためには

// c:\abc\efgというフォルダーにあるfile1.txtというファイル名のファイルを開く
FileReader aFileReader = new FileReader("c:\abc\efg\file1.txt");

// そのファイル用にBufferedReaderのインスタンスを生成する
BufferedReader in = new BufferedReader(aFileReader);

// そのファイルから1行を読み込む。
in.readLine();

// このin.readLine()を繰り返してデータを何行か読み込む。

// 最後に、そのファイルを閉じる。
in.close();

という感じでBufferedReaderを使います。


ところで、ファイルを開くときには、ファイル・ダイアログと呼ばれるウインドウ
を使って、開きたいファイルの名前などを指定するという手順を踏んでから行うの
が普通です。
このファイル・ダイアログはFileDialogというクラス名でAWTのGUI部品の
一つとして用意されています。

その使い方は、HumanInfoWindowに実装した例で説明することにします。


では、これらのクラスを使って、HumanInfoWindowの画面に入力したデータ
をファイルに保管したり、保管したファイルからデータを読み取って
画面に表示したりするようにHumanInfoWindowを改良してみましょう。

はい、改良したHumanInfoWindowのソース・コードの例が下にあります。

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

import java.awt.Button;
import java.awt.Choice;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
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 java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

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 Label labelAge = new Label();
   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;
   private String filePathName;  // 060910
   private BufferedWriter out;  // 060910
  
   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.getAge() + "歳");
      };
   };
  
   class HumanMenuActionListener implements ActionListener {
      private MenuItem menuItem;
      private HumanInfoWindow window;
      public HumanMenuActionListener(HumanInfoWindow window) {
         this.window = window;
      };
      public void actionPerformed(ActionEvent e) {
         menuItem = (MenuItem)e.getSource();
         if ("終了".equals(menuItem.getLabel())) {
            window.setVisible(false);
            window.dispose();
         }
         else if ("ファイルを開く".equals(menuItem.getLabel())) { // 060910
            FileDialog fDialog = new FileDialog(this.window, "開く", FileDialog.LOAD); // 060910
            fDialog.setVisible(true); // 060910
            filePathName = fDialog.getDirectory() + fDialog.getFile(); // 060910
            try { // 060910
               BufferedReader in = new BufferedReader(new FileReader(filePathName)); // 060910
               window.getTextFieldName().setText(in.readLine()); // 060910
               window.nengoChoice.select(Integer.parseInt(in.readLine())); // 060910
               window.getTextFieldYear().setText(in.readLine()); // 060910
               window.getTextFieldMonth().setText(in.readLine()); // 060910
               window.getTextFieldDay().setText(in.readLine()); // 060910
               window.labelResponse.setText(in.readLine()); // 060910
               in.close(); // 060910
            } catch (IOException e1) { // 060910
               System.out.println(e1); // 060910
            } // 060910

         } // 060910
         else if ("ファイルを閉じる".equals(menuItem.getLabel())) { // 060910
            try { // 060910
               out.close(); // 060910
            } catch (IOException e1) { // 060910
               System.out.println(e1); // 060910
            } // 060910
         } // 060910
         else if ("名前をつけて保存".equals(menuItem.getLabel())) { // 060910
            FileDialog fDialog = new FileDialog(this.window, "名前をつけて保存", FileDialog.SAVE); // 060910
            fDialog.setVisible(true); // 060910
            filePathName = fDialog.getDirectory() + fDialog.getFile(); // 060910
            try { // 060910
               out = new BufferedWriter(new FileWriter(filePathName, false)); // 060910
               out.write(window.getTextFieldName().getText()); out.newLine(); // 060910
               out.write(Integer.toString(window.nengoChoice.getSelectedIndex())); out.newLine(); // 060910
               out.write(window.getTextFieldYear().getText()); out.newLine(); // 060910
               out.write(window.getTextFieldMonth().getText()); out.newLine(); // 060910
               out.write(window.getTextFieldDay().getText()); out.newLine(); // 060910
               out.write(window.labelResponse.getText()); // 060910
               out.close(); // 060910
            } catch (IOException e1) { // 060910
               System.out.println(e1); // 060910
            } // 060910
         } // 060910
         else if ("上書き保存".equals(menuItem.getLabel())) { // 060910
            try { // 060910
               out = new BufferedWriter(new FileWriter(filePathName, false)); // 060910
               out.write(window.getTextFieldName().getText()); out.newLine(); // 060910
               out.write(Integer.toString(window.nengoChoice.getSelectedIndex())); out.newLine(); // 060910
               out.write(window.getTextFieldYear().getText()); out.newLine(); // 060910
               out.write(window.getTextFieldMonth().getText()); out.newLine(); // 060910
               out.write(window.getTextFieldDay().getText()); out.newLine(); // 060910
               out.write(window.labelResponse.getText()); // 060910
               out.close(); // 060910
            } catch (IOException e1) { // 060910
               System.out.println(e1); // 060910
            } // 060910
         } // 060910
      };
   };
  
   public HumanInfoWindow()  {
      super();
      setTitle("人事情報");
      setSize(400, 180);
      setLayout(null);
      Menu fileMenu = new Menu("ファイル");
      Menu editMenu = new Menu("編集");
      MenuItem openMItem = new MenuItem("ファイルを開く");
      MenuItem closeMItem = new MenuItem("ファイルを閉じる");
      MenuItem nmsaveMItem = new MenuItem("名前をつけて保存");
      MenuItem saveMItem = new MenuItem("上書き保存");
      MenuItem exitMItem = new MenuItem("終了");
      fileMenu.add(openMItem);
      fileMenu.add(closeMItem);
      fileMenu.add(nmsaveMItem);
      fileMenu.add(saveMItem);
      fileMenu.add(exitMItem);
      MenuItem clearMItem = new MenuItem("データ・クリア");
      editMenu.add(clearMItem);
      MenuBar menuBar = new MenuBar();
      menuBar.add(fileMenu);
      menuBar.add(editMenu);
      setMenuBar(menuBar);
      labelDateOfBirth.setBounds(10, 60, 80, 20);
      nengoChoice.setBounds(120, 60, 80, 20);
      nengoChoice.add("明治");
      nengoChoice.add("大正");
      nengoChoice.add("昭和");
      nengoChoice.add("平成");
      nengoChoice.add("西暦");
      getTextFieldYear().setBounds(210, 60, 40, 20);
      labelYear.setBounds(255, 60, 20, 20);
      getTextFieldMonth().setBounds(290, 60, 20, 20);
      labelMonth.setBounds(315, 60, 20, 20);
      getTextFieldDay().setBounds(350, 60, 20, 20);
      labelDay.setBounds(375, 60, 20, 20);
      labelName.setBounds(10, 90, 60, 20);
      getTextFieldName().setBounds(70, 90, 320, 20);
      instanceButton.setBounds(120,120, 160, 20);
      labelAge.setBounds(10, 150, 100, 20);
      getLabelResponse().setBounds(110, 150, 100, 20);
      add(labelDateOfBirth);
      add(nengoChoice);
      add(getTextFieldYear());
      add(labelYear);
      add(getTextFieldMonth());
      add(labelMonth);
      add(getTextFieldDay());
      add(labelDay);
      add(labelName);
      add(getTextFieldName());
      add(instanceButton);
      add(labelAge);
      add(getLabelResponse());
      labelDateOfBirth.setText("生年月日:");
      labelYear.setText("年");
      labelMonth.setText("月");
      labelDay.setText("日");
      labelName.setText("氏名:");
      instanceButton.setLabel("年齢計算");
      labelAge.setText("現在の年齢:");
      instanceButton.addActionListener(actionListener);
      HumanMenuActionListener menuActionListener = new HumanMenuActionListener(this);
      openMItem.addActionListener(menuActionListener); // 060910
      closeMItem.addActionListener(menuActionListener); // 060910
      nmsaveMItem.addActionListener(menuActionListener); // 060910
      saveMItem.addActionListener(menuActionListener); // 060910
      exitMItem.addActionListener(menuActionListener);
      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();
   }

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

今回追加された行は、その右端に「// 060910」というコメント(この行を作成
した日付06年09月10日を表したつもり)を書いてありますので、変更箇所が
すぐわかると思います。

これらの変更箇所の解説は次回行います。


とりあえず、これをEclipseで入力したあと、実行して動きを確認すること
にしましょう。

HumanInfoWindowのウインドウが開いたら、生年月日や氏名のデータを適当
に入力し、年齢を表示させた後、メニュー・バーから「ファイル」→「名前
をつけて保存」を選択しましょう。
ファイル・ダイアログが開きますね。そこで、ファイル名を指定(入力)
して「保存」ボタンをクリックしてみてください。

次にHumanInfoWindowのウインドウをいったん閉じたあと、再度実行して開き
ましょう。
HumanInfoWindowのウインドウが開いたら、「ファイル」→「ファイルを開く」
を選択しましょう。
ファイル・ダイアログが開きますね。そこで、さきほど入力したファイル名
を選択して「開く」ボタンをクリックしてみてください。
生年月日や氏名や年齢が正しく復元されますね。

今度は、データ(どれかのテキスト・フィールド)を少し書き換えてから、
「ファイル」→「上書き保存」を選択しましょう。

さきほどと同じようにいったんHumanInfoWindowのウインドウをいったん閉
じたあと、再度実行して開きましょう。
HumanInfoWindowのウインドウが開いたら、「ファイル」→「ファイルを開く」
を選択しましょう。
ファイル・ダイアログが開いたら、再度さきほどのファイル名を選択して
「開く」ボタンをクリックしてみてください。
表示されるデータを確認しましょう。



========================================================
◆ 02.文法解説 [識別子]
========================================================

クラス名や変数名、メソッド名などの名前のことを識別子(dentifier)と
いいます。
識別子は半角文字を使って自由に命名することができますが、以下の規則
に従う必要があります。

- 最初の1文字は英字(A〜Zおよびa〜z)、_(アンダー・スコア)、$のいずれか
  を使用します。
- 2文字目以降は、英字(A〜Zおよびa〜z)、_(アンダー・スコア)、$、および
  数字(0〜9)を使用します。
- 予約語(classやifなどJavaのキーワードとして予め予約済みの用語)と同じ
  名前は使用できません。

(注) 最新のJavaでは英字以外にも、カナや漢字でもUnicodeで表現できる文字
は識別子に使用可能になっています。
しかし、ソース・コードの見やすさや、今後の国際性(プログラムが海外でも
使用される可能性)を考えると日本の文字の識別子は好ましくありません。
上記の規則に従ったほうが無難でしょう。


予約語には以下のようなものがあります(詳しい使い方は追々学んでいきます)。

abstract   continue   for          new         switch
assert     default    if           package     synchronized
boolean    do         goto         private     this
break      double     implements   protected   throw
byte       else       import       public      throws
case       enum       instanceof   return      transient
catch      extends    int          short       try
char       final      interface    static      void
class      finally    long         strictfp    volatile
const      float      native       super       while                      
なお、constやgotoは実際には使用されていませんが、C++からの誤用を防ぐため
に、間違って使用してしまった場合にJavaのコンパイラーがエラーを発生させる
などの仕組みがあります。

また、クラス名の最初の文字は大文字にするのが標準になっており、変数名や
メソッド名(コンストラクターは除く)の最初の文字は小文字にするのが標準
になっています。
(標準というのは推奨されているという意味であって、必ずそうしなければなら
ないというわけではありません。)


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



======================================================
◆ 03.演習問題
======================================================

今回のHumanInfoWindowのソース・コードで新たに追加された行がそれぞれ
どういう働きをするのか考えてください。

また、ファイルに書き出されるデータの構造がどうなっているのか考えてみ
てください。



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