広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2011年02月12日

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

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


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


========================================================
◆ 01.データベースを使用するアプリケーションの開発(続き)
========================================================

では、次にComboBoxModelOfDepartmentクラスの説明をしていき
ましょう。

Swingでは、ユーザー・インターフェースのオブジェクトと
ユーザー・インターフェースに表示したいデータを入れるオ
ブジェクトを分離して管理するという考え方をしていて、
JComboBoxに対してはComboBoxModelというオブジェクトが
データを入れるオブジェクトだったのでしたね。

ComboBoxModelOfDepartmentがそのComboBoxModelの実装例でした。

今の場合、JComboBoxには部門の名前のリストを表示したいので、
ComboBoxModelOfDepartmentには部門の情報を持たせる必要があり
ます。
また、JComboBoxにデータを表示させるために、JComboBoxと
ComboBoxModelの間のデータの受け渡しのためのメソッドの
実装が必要になります。

それをComboBoxModelOfDepartmentの実装例で説明します。


ComboBoxModelOfDepartmentのコーディング例を再度提示します。
--------------------------------------------------------
package jp.co.flsi.lecture.ui.model;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import java.util.Vector;
import jp.co.flsi.lecture.entity.Department;

public class ComboBoxModelOfDepartment extends AbstractListModel implements
ComboBoxModel {
   private Vector departmentList;
   private String selection;

   public void setDepartmentList(Vector aDepartmentList) {
      departmentList = aDepartmentList;
   }

   public Vector getDepartmentList() {
      return departmentList;
   }

   public Object getSelectedItem() {
      return selection;
   }

   public void setSelectedItem(Object anItem) {
      selection = (String)anItem;
   }

   public Object getElementAt(int index) {
      return ((Department) getDepartmentList().elementAt(index)).getDepartmentName();
   }

   public int getSize() {
      return getDepartmentList().size();
   }

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

ComboBoxModelOfDepartmentはAbstractListModelのサブクラスと
し、かつComboBoxModelというインターフェイスを実装するもの
として作りましたので、class文には8〜9行目
--------------------------------------------------------
public class ComboBoxModelOfDepartment extends AbstractListModel implements
ComboBoxModel {
--------------------------------------------------------
の通り、extends AbstractListModel(AbstractListModelを拡張する)
とimplements ComboBoxModel(ComboBoxModelを実装する)の指定が
あります。

このソース・コードの中に定義されているメソッドのうち、
public Object getElementAt(int index)

public int getSize()
の2つはListModelインターフェースのもので、
public Object getSelectedItem()

public void setSelectedItem(Object anItem)
の2つははComboBoxModelインターフェースのものです。

これらのメソッドはJComboBoxとComboBoxModelの間のデータの
受け渡しのために、必ず実装しなければならないもので、
JComboBoxに表示したい内容に合わせて実装する必要があります。


これらのメソッドの意味を以下に簡単に述べておきます。

public Object getElementAt(int index)
は指定されたインデックス(index = 0から始まる番号)の要素を
取り出す(戻り値として返す)メソッドです。

┌補足─────────────────────────┐
 配列やリストの中の個々のデータを(配列やリストの)要素
 (element)といいますが、何番目の要素かを表す数をインデッ
 クスといい、インデックスは0から始まる整数になります。
 JComboBoxに表示したいデータは、通常、配列やリストの形で
 用意しておきます。
└───────────────────────────┘

JComboBoxはこのメソッドを呼び出すことによって、表示すべきデー
タを取り出します。
そしてインデックスが0のものをリストの1行目に、インデックスが1
のものをリストの2行目に、・・・という順番で表示します。

public int getSize()
は要素の数を返すメソッドです。
JComboBoxはこのメソッドを呼び出すことによって、上の
getElementAt()メソッドで取り出すデータの個数を決定しま
す。
たとえば、getElementAt()メソッドで取り出すデータがインデッ
クス0のものから5のものまであったとすると、全部で6個の要素が
取り出せるわけですから、getSize() が返す数を6にしておけば
すべての要素が表示されます。
間違えてgetSize() が返す数を5にしてしまうと実際の要素数より
1つ少ないので、最後の要素が表示されません。
逆にgetSize() が返す数を実際の要素数より大きくしてしまうと、
存在しない要素を取り出そうとしたときにエラーを発生することに
なってしまいます。

public Object getSelectedItem()
は現在選択されている項目を取り出すメソッドです。
JComboBoxはこのメソッドを呼び出して取り出したデータを、選択
されている項目として表示します。

public void setSelectedItem(Object anItem)
は選択された項目を保管するためのメソッドです。
JComboBoxのリスト上で項目が選択されたときにこのメソッドが
呼び出されます。(故意にこのメソッドを呼び出して選択項目を
変更するようにプログラムを編集することもできます。)

このメソッドの中では、新しく選択された項目が引数として渡され
るので、それをどこかに保管しておき、その保管しておいたものを
上のgetSelectedItem()メソッドで返すようにするのが基本的な実装
です。


では、実際の実装例を説明していきましょう。

まず、ComboBoxModelOfDepartmentには部門の情報、すなわち
Departmentオブジェクトの情報を持たせたいわけですが、前回まで
に説明したようにDepartmentDbManagerクラスがデータベースから
データを取り出してDepartmentオブジェクトのリストを構築するの
でした。

そのDepartmentオブジェクトのリストをComboBoxModelOfDepartmentに
渡すことにして、ComboBoxModelOfDepartmentにDepartmentオブジェク
トのリストを保管するためのフィールドを用意します。

それが10行目
--------------------------------------------------------
private Vector departmentList;
--------------------------------------------------------
です。

この変数が、DepartmentDbManagerの11行目
--------------------------------------------------------
private Vector departmentList = new Vector();
--------------------------------------------------------
と同じVector型の変数になっていることを確認してください。

ついでに変数名もまったく同じ名前にしていますが、これは
わかりやすくするためです。
互いに継承関係もない、異なるクラスの変数ですから、変数名が
同じだからといっても、それだけでは互いに関係はありません。

次に、13〜19行目
--------------------------------------------------------
public void setDepartmentList(Vector aDepartmentList) {
   departmentList = aDepartmentList;
}

public Vector getDepartmentList() {
   return departmentList;
}
--------------------------------------------------------
を見てみましょう。

これが、10行目のdepartmentListに対するsetメソッドおよびget
メソッドですね。
setDepartmentList()メソッドは、引数に指定されたVectorオブ
ジェクトをdepartmentListに代入し、getDepartmentList()メソッ
ドはdepartmentListを戻り値として返すだけの平凡なメソッドです。

このsetDepartmentList()メソッドを使って、DepartmentDbManagerの
departmentListをComboBoxModelOfDepartmentのdepartmentListに代入
するということを後で行います。

次に、33〜35行目
--------------------------------------------------------
public int getSize() {
   return getDepartmentList().size();
}
--------------------------------------------------------
を見てみましょう。

getSize()メソッドは、JComboBoxに表示したい要素の数を返すよう
に実装しなければならないのでしたから、departmentListの要素数
を返すようにコーディングしています。

size()というのはVectorのメソッドで、Vectorオブジェクトの中の
要素の数を返すメソッドです。

getDepartmentList()メソッドがdepartmentListのgetメソッド、つ
まりdepartmentListを取り出す(戻り値として返す)メソッドで、
departmentListがVector型の変数、つまりVector型のオブジェクト
を代入するための変数であることは、先ほど述べた通りです。

次に、29〜31行目
--------------------------------------------------------
public Object getElementAt(int index) {
   return ((Department) getDepartmentList().elementAt(index)).getDepartmentName();
}
--------------------------------------------------------
を見てみましょう。
getElementAt(int index)は、JComboBoxのリスト上のindex番目
(index + 1 行目)に表示したい要素を返すように実装しなけれ
ばならないのでしたが、実際にJComboBoxに表示したいのは部門名
です。
したがって、departmentListのindex番目の要素を取り出して
その部門名の値を返すようにコーディングしています。

getDepartmentList().elementAt(index)は、VectorのelementAt()
メソッドを呼び出しているわけですが、このelementAt()メソッド
は引数に指定したインデックスの要素をVectorオブジェクトの中
から取り出すメソッドです。
そしてその前に(Department)をつけているのは、Department型に
キャストするためです。
キャストというのは、オブジェクトの型を変換するものでしたね
(忘れた人は008号を参照のこと)。

VectorのelementAt()メソッドは、戻り値をObject型として返しま
すが、そのままだとDepartmentのメソッド(ここではgetDepartmentName()
メソッド)を実行することができません。
(実際にこのVectorオブジェクトにはいっている要素はDepartmentオ
ブジェクトなのですが、戻り値として返されるときにObject型扱いさ
れ、Object型にはgetDepartmentName()などのDepartmentのメソッドは
ありませんのでgetDepartmentName()メソッドが実行できないのです。)

そこで、Department型にキャストしてからgetDepartmentName()メ
ソッドを呼び出しているのです。
getDepartmentName()はDepartmentのメソッドで、部門名を返す
メソッドでしたね。


┌補足─────────────────────────┐
 Vector<Department>というように<>の中にクラス名を指定する
 ことによってVectorオブジェクトに入れる要素の型を指定する
 ことができることは、前回お話した通りです。
 その場合にはelementAt()メソッドが返すオブジェクトの型も
 <>で指定したものになります。
 詳しくは後述します。
└───────────────────────────┘


次に、25〜27行目
--------------------------------------------------------
public void setSelectedItem(Object anItem) {
   selection = (String)anItem;
}
--------------------------------------------------------
を見てみましょう。

setSelectedItem()メソッドは、JComboBoxのリスト上で項目が
選択されたときに選択された項目を保管すべく実装しておくもの
でした。
ここでは、selectionという変数に、選択された項目(引数で渡さ
れる)を代入することによって保管していますが、JComboBoxのリ
スト上の項目は部門名であり、String型なので「(String)anItem」
というようにString型にキャストしています。

なお、selectionという変数は11行目
--------------------------------------------------------
private String selection;
--------------------------------------------------------
で宣言しています。


次に、21〜23行目
--------------------------------------------------------
public Object getSelectedItem() {
   return selection;
}
--------------------------------------------------------
を見てみましょう。

getSelectedItem()メソッドは、現在選択されている項目を取り
出すべくselectionに保管された値をそのままreturnで返すよう
に実装しています。

以上で、ComboBoxModelOfDepartmentのソース・コードは理解で
きたことと思います。


では、次に、HumanResourceEntryPaneのソース・コードの中の
getComboBox_1()メソッドの編集内容を見てみましょう。

--------------------------------------------------------
   private JComboBox getComboBox_1() {
      if (comboBox_1 == null) {
            DepartmentDbManager aDbm = new DepartmentDbManager();
            aDbm.getAllData();
            ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
            model.setDepartmentList(aDbm.getDepartmentList());
            comboBox_1 = new JComboBox(model);
            comboBox_1.setSelectedIndex(0);
      }
      return comboBox_1;
   }
--------------------------------------------------------

1行ずつ順番に説明していきます。

--------------------------------------------------------
if (comboBox_1 == null) {
--------------------------------------------------------
遅延生成(013号を参照)のためのif文です。
comboBox_1がnullのときはJComboBoxのインスタンスがまだ生成
されていないことを意味しますので、以下のコードの中で生成
します。

--------------------------------------------------------
DepartmentDbManager aDbm = new DepartmentDbManager();
--------------------------------------------------------
DepartmentDbManagerのインスタンスを生成し、aDbmという変数
に代入しています。

--------------------------------------------------------
aDbm.getAllData();
--------------------------------------------------------
DepartmentDbManagerのgetAllData()メソッドを実行しています。

getAllData()メソッドは、データベースのDEPARTMENTテーブルの
中のすべてのデータを読み取って、それぞれDepartmentのインス
タンスとして、Departmentのリスト(Vector型のオブジェクト)
に入れていくという作業を行うものでした。

--------------------------------------------------------
ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
--------------------------------------------------------
ComboBoxModelOfDepartmentのインスタンスを生成し、modelという
変数に代入しています。

--------------------------------------------------------
model.setDepartmentList(aDbm.getDepartmentList());
--------------------------------------------------------
aDbm.getDepartmentList()はDepartmentDbManagerのdepartmentList
フィールドのgetメソッドですから、DepartmentDbManagerが持つ
Departmentのリストを返します。
それを引数としてComboBoxModelOfDepartmentのsetDepartmentList()
メソッドを呼び出していますが、これはDepartmentDbManagerの
departmentListをComboBoxModelOfDepartmentのdepartmentList
に代入するということを意味しますね。

これによって、DepartmentDbManagerがデータベースから取って
きた部門の情報がComboBoxModelOfDepartmentに渡されるわけです。

--------------------------------------------------------
comboBox_1 = new JComboBox(model);
--------------------------------------------------------
JComboBoxのインスタンスを生成してcomboBox_1という変数に
代入しています。

これも遅延生成の過程の一部です。

この時点でcomboBox_1の値はnullではなくなりますので、
その後はgetComboBox_1()が呼ばれてもJComboBoxのインス
タンスは生成されません。

ここではJComboBoxのコンストラクターの引数にmodelが指定
されていますが、このように指定すると、生成されたJComboBox
のインスタンスは、表示するデータをmodelから取り出し、
(項目の選択が変わったなどの)データに関わる変化をmodelに
伝えるようになります。

--------------------------------------------------------
comboBox_1.setSelectedIndex(0);
--------------------------------------------------------
このようにJComboBoxのsetSelectedIndex()メソッドを呼び出すと、
引数に指定したインデックスの項目を選択状態にしてくれます。

ここでは引数に0を指定していますのでJComboBoxのリスト上の
1行目の項目が選択状態になります。
(インデックスは0から始まりますので、0は先頭行、つまり1行目
を意味します。)

ちなみに、もし引数に-1を指定した場合は、「何も選択しない」
ことになります。

--------------------------------------------------------
}
--------------------------------------------------------
これは、if文の終わりの「}」です。つまり、この上の行までが
comboBox_1 == null
のときに実行されることになります。

--------------------------------------------------------
return comboBox_1;
--------------------------------------------------------
getComboBox_1()メソッドの戻り値としてcomboBox_1の値を返し
ます。



では、このgetComboBox_1()メソッドはどこで呼び出されている
かというと、VisualEditorが自動生成したソース・コードの中で
呼び出されています。

詳しく説明しているとあまりにも時間がかかってしまいますので、
概略だけ説明すると、HumanResourceEntryPaneのコンストラクター
の中でinitialize()というメソッド(初期設定を行うためのメソッ
ド)を呼んでおり、initialize()メソッドの中でgetJPanel()メソッ
ド、getJPanel()メソッドの中でgetComboBox_1()メソッドという順
に呼び出しています。
そしてHumanResourceEntryPane自体は、HumanResourceJFrameに貼り
付けてありますから、HumanResourceJFrameのアプリケーションを
起動したときにHumanResourceEntryPaneのコンストラクターが呼び
出される(HumanResourceEntryPaneのインスタンスが生成される)
ようなソース・コードになっています。

力のある人は自動生成されたソース・コードを自分で全部調べてみ
てください。

そこまで力はないと思う人もご安心ください。
このメールマガジンを読んでいるうちに、段々とソース・コードの
分析力もついてきます。


では、これまでに説明したソース・コードを実際にEclipseに入力/
編集して動作を確認してみましょう。
(以下のEclipseへの入力/編集作業を既に自力で終えている人は
適時、読み飛ばしてください。)


では、まずEclipseを起動してください。


Departmentクラスのソース・コードから入力していくことにしま
しょう。
このクラスはjp.co.flsi.lecture.entityというパッケージに入れ
ることにしていましたから、最初に、jp.co.flsi.lecture.entity
パッケージを作っておきましょう


┌───────────────────────────┐
     jp.co.flsi.lecture.entityパッケージの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーのJStudy1(プロジェクト)を
右クリックし、「新規」→「パッケージ」を選択します。

(2) 「新規Javaパッケージ」ウインドウで「ソース・フォルダー」
の欄に「JStudy1/src」がはいっていることを確認し、「名前」の欄
に「jp.co.flsi.lecture.entity」と入力し、「完了」ボタンをクリ
ックします。

これで、JStudy1プロジェクトの配下にjp.co.flsi.lecture.entityパ
ッケージが作られましたね。

次に、このパッケージの中にDepartmentクラスを作成しましょう。


┌───────────────────────────┐
     Departmentクラスの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーにできたjp.co.flsi.lecture.entity
(パッケージ)を右クリックし、「新規」→「クラス」を選択します。

(2) 「新規Javaクラス」ウインドウで「ソース・フォルダー」の欄
に「JStudy1/src」がはいっていることを確認し、「パッケージ」の
欄に「jp.co.flsi.lecture.entity」がはいっていることを確認し、
「名前」の欄に「Department」と入力します。

(なお、「どのメソッド・スタブを作成しますか?」の
「public static void main(String[] args)」や
「スーパークラスからのコンストラクター」にはチェックマークは
入れないでください。)

(3) 「完了」ボタンをクリックします。

そうすると、Departmentのエディターが開きますので、Departmentの
ソース・コード(下に再度提示します)を完成させましょう。

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

public class Department {
   private int departmentNumber;
   private String departmentName;
   private String location;

   public void setDepartmentNumber(int departmentNumber) {
      this.departmentNumber = departmentNumber;
   }
  
   public int getDepartmentNumber() {
      return departmentNumber;
   }
  
   public void setDepartmentName(String departmentName) {
      this.departmentName = departmentName;
   }
  
   public String getDepartmentName() {
      return departmentName;
   }
  
   public void setLocation(String location) {
      this.location = location;
   }
  
   public String getLocation() {
      return location;
   }

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

続いてComboBoxModelOfDepartmentのソース・コードを入力して
いくことにしますが、このクラスはjp.co.flsi.lecture.ui.model
というパッケージに入れることにしていましたから、
jp.co.flsi.lecture.ui.modelパッケージを作っておきましょう


┌───────────────────────────┐
     jp.co.flsi.lecture.ui.modelパッケージの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーのJStudy1(プロジェクト)を
右クリックし、「新規」→「パッケージ」を選択します。

(2) 「新規Javaパッケージ」ウインドウで「ソース・フォルダー」
の欄に「JStudy1/src」がはいっていることを確認し、「名前」の
欄に「jp.co.flsi.lecture.ui.model」と入力し、「完了」ボタン
をクリックします。

これで、JStudy1プロジェクトの配下にjp.co.flsi.lecture.ui.model
パッケージが作られましたね。

次に、このパッケージの中にComboBoxModelOfDepartmentクラスを
作成しましょう。


┌───────────────────────────┐
     ComboBoxModelOfDepartmentクラスの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーにできたjp.co.flsi.lecture.ui.model
(パッケージ)を右クリックし、「新規」→「クラス」を選択します。

(2) 「新規Javaクラス」ウインドウで「ソース・フォルダー」の欄に
「JStudy1/src」がはいっていることを確認し、「パッケージ」の欄に
「jp.co.flsi.lecture.ui.model」がはいっていることを確認し、
「名前」の欄に「ComboBoxModelOfDepartment」と入力し、
「スーパークラス」の右側の「参照」ボタンをクリックします。

(3) 「スーパークラスの選択」ウインドウの入力欄に「AbstractListModel」
を入力するとその下の「一致する項目」の欄に「AbstractListModel - javax.swing」
というのが表示されるのでそれを選択(クリック)し、「OK」ボタンを
クリックします。
これで、「スーパークラス」の欄に「javax.swing.AbstractListModel」
が入力されたことを確認してください。

(4) 「インターフェース」の右側の「追加」ボタンをクリックします。

(5) 「実装されたインターフェースの選択」ウインドウの入力欄に
「ComboBoxModel」を入力するとその下の「一致する型」の欄に
「ComboBoxModel- javax.swing」というのが表示されるのでそれを
選択(クリック)し、「追加」ボタンをクリックしてから「OK」ボタ
ンをクリックします。

┌補足─────────────────────────┐
上の「実装されたインターフェースの選択」という翻訳は、ずば
り言って「実装されるインターフェースの選択」の間違いですね
(原本は「Implemented Interfaces Selection」)。
これから実装するという段階なのに、既に「実装された」という
過去形になっているのがおかしい(本当は「実装される」という
受け身形である)ことは誰にもわかることだと思いますが、
さらっと見流すことにしましょう。

「Eclipseはこれだけ優れた機能を豊富に持っているのに何で無料
なの?」という驚きに比べれば、こんな誤訳なんて大して気になら
ないものです。
└───────────────────────────┘

(6) 「どのメソッド・スタブを作成しますか?」の欄は「継承された
抽象メソッド」だけにチェックマークがはいっている状態にして
「完了」ボタンをクリックします。

(抽象メソッドは実装されていないメソッドなので、これから実装
する必要があります。
また、「メソッド・スタブ(method stub)」というのは、中身(ロジ
ック部分)が空っぽのメソッドのことです(詳しくは後述)。)

そうすると、ComboBoxModelOfDepartmentのエディターが開いて
下記のようなソース・コードが表示されますね。

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

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;

public class ComboBoxModelOfDepartment extends AbstractListModel implements
      ComboBoxModel {

   public Object getSelectedItem() {
      // TODO 自動生成されたメソッド・スタブ
      return null;
   }

   public void setSelectedItem(Object anItem) {
      // TODO 自動生成されたメソッド・スタブ

   }

   public Object getElementAt(int index) {
      // TODO 自動生成されたメソッド・スタブ
      return null;
   }

   public int getSize() {
      // TODO 自動生成されたメソッド・スタブ
      return 0;
   }

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

ここで、「TODO 自動生成されたメソッド・スタブ」とコメント
が書かれているメソッドは、各インターフェースのうち未実装の
メソッドです。
メソッド・スタブというのは、このように中身(自分でプログ
ラミングすべき部分=ロジックの部分)を除いたソース・コード
が提供されるもので、このメソッドの中身は自分で実装(プログ
ラミング)する必要があります。

そういう意味で、このコメントには「TODO」(= to do)と書い
てあります。
(ちなみに、アメリカのビジネスマンはよくTO-DO Listと称して、
やるべきこと(to do)を紙に列挙する習慣があります。)


それでは、このソース・コード内のTODOと書かれている行、およ
びreturn文の行を書き換えて、ComboBoxModelOfDepartmentのソー
ス・コードを完成させましょう。

完成したソース・コードを下に再度提示します。

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

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import java.util.Vector;
import jp.co.flsi.lecture.entity.Department;

public class ComboBoxModelOfDepartment extends AbstractListModel implements
ComboBoxModel {
   private Vector departmentList;
   private String selection;

   public void setDepartmentList(Vector aDepartmentList) {
      departmentList = aDepartmentList;
   }

   public Vector getDepartmentList() {
      return departmentList;
   }

   public Object getSelectedItem() {
      return selection;
   }

   public void setSelectedItem(Object anItem) {
      selection = (String)anItem;
   }

   public Object getElementAt(int index) {
      return ((Department) getDepartmentList().elementAt(index)).getDepartmentName();
   }

   public int getSize() {
      return getDepartmentList().size();
   }

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

ここで、エディター内のComboBoxModelOfDepartmentの文字列の
下に橙色のアンダーラインが表示されて、その行の左側に警告の
マーク(丸みがかった橙色の三角形の中に!がはいったマーク)
が表示されますが、これは無視してください。問題はありません。

とりあえずマークの上にマウス・ポインターを重ねると「シリア
ライズ可能クラス・・・(以下省略)・・・」という説明が出
ますが、これを解説するためには以前にも触れたように直列化
(serialization)の話をしなければならないので、この解説は
あと回しにします。
今回のアプリケーションでは直列化の機能は利用しないので、
この警告は無視してかまいません。
(直列化については、後にJavaBeansの話をするときに説明いた
します。)

どうしても気になる人は、マークの上にマウス・ポインターを重ね
たときに表示されるメッセージの中で「デフォルト・シリアル・
バージョンIDの追加」というのを選択(クリック)すれば、

--------------------------------------------------------
private static final long serialVersionUID = 1L;
--------------------------------------------------------

というコードが自動的に追加され、警告マークが消えます。
(この右辺の1Lという数は直列化に関係するバージョンを指定する
ものであり、必要に応じて変える必要がありますが、今のところは
気にせずに1Lにしてかまいません。)

今後はとくに断りませんが、他のクラスで同じ警告マークが出た
ときにも自主的に上記の操作で対処してもらってかまいません。


それからこのComboBoxModelOfDepartmentのソース・コード内では
Vectorのところにも警告のマークが表示されているはずですが、
これは、Vectorの代わりに
Vector<クラス名>
という型(このように<>がついている型を総称型(generic type)と呼ぶ)
を使ったほうが望ましい(このほうがコンパイラーが細かいチェック
をしてくれる)からなのですが、詳しいことは後述します。
今回はこの警告マークは無視して下さい。


では、続いてDbManagerクラスのソース・コードを入力していく
ことにしましょう。
このクラスはjp.co.flsi.lecture.dbというパッケージに入れる
ことにしていましたから、まずは、jp.co.flsi.lecture.dbパッ
ケージを作っておきましょう


┌───────────────────────────┐
     jp.co.flsi.lecture.dbパッケージの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーのJStudy1(プロジェクト)を
右クリックし、「新規」→「パッケージ」を選択します。

(2) 「新規Javaパッケージ」ウインドウで「ソース・フォルダー」
の欄に「JStudy1/src」がはいっていることを確認し、「名前」の欄に
「jp.co.flsi.lecture.db」と入力し、「完了」ボタンをクリック
します。

これで、JStudy1プロジェクトの配下にjp.co.flsi.lecture.dbパッ
ケージが作られましたね。

次に、このパッケージの中にDbManagerクラスを作成しましょう。


┌───────────────────────────┐
     DbManagerクラスの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーにできたjp.co.flsi.lecture.db
(パッケージ)を右クリックし、「新規」→「クラス」を選択しま
す。

(2) 「新規Javaクラス」ウインドウで「ソース・フォルダー」の欄
に「JStudy1/src」がはいっていることを確認し、「パッケージ」の
欄に「jp.co.flsi.lecture.db」がはいっていることを確認し、
「名前」の欄に「DbManager」と入力します。

(3) 「完了」ボタンをクリックします。

そうすると、DbManagerのエディターが開きますので、DbManagerの
ソース・コード(下に再度提示します)を完成させましょう。

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

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DbManager {
   protected static Connection conn = null;
   protected String driver = "org.h2.Driver";
   protected String url = "jdbc:h2:tcp://localhost/~/test";
   protected String dbUser = "sa";
   protected String dbPassword = "";

   protected void connect() throws java.sql.SQLException {
      try {
         if(conn == null || conn.isClosed()) {
            Class.forName(driver);
            conn = DriverManager.getConnection
                        (url, dbUser, dbPassword);
            conn.setAutoCommit(false);
         }
      } catch(ClassNotFoundException ex) {
         ex.printStackTrace();
      }
   }

   protected void disconnect() {
      try {
         conn.close();
      } catch(SQLException ex) {
         ex.printStackTrace();
      }
   }

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


次に、同じパッケージの中にDepartmentDbManagerクラスを作成
しましょう。


┌───────────────────────────┐
     DepartmentDbManagerクラスの作成
└───────────────────────────┘

(1) パッケージ・エクスプローラーにできたjp.co.flsi.lecture.db
(パッケージ)を右クリックし、「新規」→「クラス」を選択します。

(2) 「新規Javaクラス」ウインドウで「ソース・フォルダー」の欄
に「JStudy1/src」がはいっていることを確認し、「パッケージ」の
欄に「jp.co.flsi.lecture.db」がはいっていることを確認し、
「名前」の欄に「DepartmentDbManager」と入力します。

(3) 「完了」ボタンをクリックします。

そうすると、DepartmentDbManagerのエディターが開きますので、
DepartmentDbManagerのソース・コード(下に再度提示します)を
完成させましょう。

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

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import jp.co.flsi.lecture.entity.Department;

public class DepartmentDbManager extends DbManager {
   private Vector departmentList = new Vector();

   public Vector getDepartmentList() {
      return departmentList;
   }

   public void getAllData() {
      {
         try {
            connect();
            Statement selectSql = conn.createStatement();
            ResultSet rs = selectSql.executeQuery("SELECT * FROM DEPARTMENT");
            while (rs.next()) {
               Department aDepartment = new Department();
               aDepartment.setDepartmentNumber(rs.getInt("DEPART_NUM"));
               aDepartment.setDepartmentName(rs.getString("DEPART_NAME"));
               aDepartment.setLocation(rs.getString("LOCATION"));
               getDepartmentList().addElement(aDepartment);
            }
            selectSql.close();
            disconnect();
         }
         catch (SQLException exception) {
            exception.printStackTrace();
         }
      }
   }
  
}
--------------------------------------------------------


最後に、jp.co.flsi.lecture.uiパッケージの中の編集です。
HumanResourceEntryPaneのソース・コードの中の以下の部分
--------------------------------------------------------
   private JComboBox getComboBox_1() {
      if (comboBox_1 == null) {
         comboBox_1 = new JComboBox();
      }
      return comboBox_1;
   }
--------------------------------------------------------

を次のように編集しましょう。
--------------------------------------------------------
   private JComboBox getComboBox_1() {
      if (comboBox_1 == null) {
            DepartmentDbManager aDbm = new DepartmentDbManager();
            aDbm.getAllData();
            ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
            model.setDepartmentList(aDbm.getDepartmentList());
            comboBox_1 = new JComboBox(model);
            comboBox_1.setSelectedIndex(0);
      }
      return comboBox_1;
   }
--------------------------------------------------------

なお、上記のソース・コードにはimport文を書いてありませんから、
コピー&ペーストで上のコードをそのまま貼り付けたりすると、
DepartmentDbManagerやComboBoxModelOfDepartmentにエラーのマー
ク(赤いアンダーライン)がつくはずです。

必要なimport文を挿入させるためにコンテンツ・アシストの機能を
使用(たとえば、DepartmentDbManagerと入力してCtrlキーを押し
ながらスペース・キーを押す)してください。



┌───────────────────────────┐
     動作確認
└───────────────────────────┘

(1) 入力/編集したソース・コードをすべて保管(Ctrl + S)して
ください。

(2) H2 Consoleを立ち上げるなどしてH2 Database EngineのRDBMSを
起動してください。
(もし、JDBCドライバーをまだEclipseのクラスパスに登録していな
い人は、ここでvol.037を参照して登録しておいてください。)

(3) HumanResourceJFrameを実行してください。

(4) 「所属部署」のJComboBoxの右側の逆三角形ボタンをクリック
して(このとき表示されるリストをドロップダウン・リストという)、
「社長直属」、「総務課」、「営業課」がリストされていることを
確認してください。
また、そのうちの一つを選択すると、ドロップダウン・リストが閉じ
て、選択した項目が表示されることを確認してください。

(5) HumanResourceJFrameのウインドウは閉じるボタン(×マークの
ボタン)をクリックして閉じましょう。



では、さらにアプリケーションの開発を続けていきましょう。

HumanResourceEntryPaneの新規登録の画面には、あと登録作業のため
のボタンを付けて、ボタンをクリックすると、入力されたデータを
データベースのEMPLOYEEテーブルに書き込むように、プログラミング
する必要があります。

このため、ボタンがクリックされたときに必要な操作を行うように、
以前(010号などで)お話したActionListenerのactionPerformed()
メソッドを実装しますが、また次回からのお話にします。


では、また来週。



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

一般に、データベースにアクセスするときには、

(1) データベースへのconnect
(2) データの検索/追加/更新/削除などの処理
(3) データベースへのdisconnect

の順番に実行することになります。
このとき(1)のconnectに失敗した場合は(2)以降は実行できませんの
で、(1)でSQLException等を検出したときは(2)以降は実行しないよう
にプログラミングするのが普通です。
今回のアプリケーションでは、DepartmentDbManagerクラスの
getAllData()メソッドの中でスーパークラス(DbManager)の
connect()メソッドを実行し、データの検索をしたあと、
スーパークラス(DbManager)のdisconnect()メソッドを実行して
いますが、もしスーパークラスのconnect()メソッドがSQLException
を投げるとDepartmentDbManagerクラスのgetAllData()メソッドの
中の
       connect();
の行より後は実行されず、したがって、データの検索やdisconnect()
メソッドは実行されないことになります。
このように、例外の機能を利用すると、わざわざ自分で(2)以降を実行し
ないようにプログラミングしなくてすみます。

このとき注意しなければならないことは、もしスーパークラスのconnect()
メソッドの内部でSQLException等をcatchしてしまい、connect()メソッド
の外にthrowsしないと、DepartmentDbManagerクラスのgetAllData()メソッ
ドの中では、それを検出できません。
すると、connectに失敗していてもデータの検索を実行しようとしてしまい
ます(当然データの検索にも失敗しますから二度手間になります)。
したがって、connect()メソッドの内部でcatchしてしまうのは
不都合なのです。

一方、disconnect()メソッドの内部でSQLException等が発生した場合は
それをdisconnect()メソッドの内部でcatchしても不都合はありません。
なぜならば、その時点ではデータ処理(今回のアプリケーションでは
データの検索) は終わった後なので、たとえdisconnectに失敗しても
肝心の仕事は終わっているからです。
disconnect()メソッドの中でcatchして、記録を残す(今回のアプリケー
ションでは、exception.printStackTrace()を実行していますが、後に
ログを書いて記録するという方法もお話します)だけで十分です。

という訳で、DbManagerのconnect()メソッドでは外にSQLExceptionを
throwsし、disconnect()メソッドではthrowsせずに、代わりに
disconnect()メソッドの内部でSQLExceptionをcatchするという、
非対象的な処理でかまわないのです。



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