モデルは中身で (3) [Rendererクラスの改造: CheckBoxCellRenderer]
2002-02-03
さてさて、ListModelに注目して、チェックボックス付きリストボックスを実現する第3回目です。前回は、CheckBoxListModelの作りについて述べました。今回は、残りのCheckBoxCellRenderer、ListCheckerクラスについて説明して、全ての部品をそろえてしまうことにしましょう。最後に、ListCheckerを導入したことにより発生した初期化のコーリングシーケンスについて言及しておきます。
前回同様、CheckBoxListModelで保持する、チェックボックスの選択状態とリスト項目の有効無効の2つの状態を、以下ではそれぞれ、「チェック状態」、「有効状態」と表記します。
■筆を選んでペッタン
JListを構成するMVCのViewは、ListCellRendererインタフェースを通してアクセスされます。デフォルトの実装として、DefaultListCellRendererクラスが用意されています。今回、チェックボックスを描画する必要がありますから、その処理を行うRendererクラスを作成することになります。既存のクラスをそのまま使えれば一番いいのですが、Modelという描かれるものが、ふさわしい筆を選ぶ、ということになります。それがCheckBoxCellRendererクラスになります。
ListCellRendererインタフェースを見ると、実装する必要のあるメソッドは、1つだけであることがわかります。paintやupdateといった描画や更新のためのメソッドは作成することを要求されていせん。非常に奇妙な感じがするのではないでしょうか。
|
public Component getListCellRendererComponent(
JList
list,
Object
value,
int index,
boolean
isSelected,
boolean
cellHasFocus
)
|
valueを描画するためのコンポーネントを返す |
このメソッドはComponentを返すように作ります。このComponentの中身は、リストの1項目分の表示内容になります。それが、そのままリストの項目のあるべき位置に、はんこを押すように描画され、そのような処理が全項目分繰り返されるわけです。
■さぁさぁ、調整
ListCellRendererのgetListCellRendererComponentメソッドでは、引数に従って状態を示すように設定された部品をComponentに並べていけばいいわけです。CheckBoxCellRendererでは、JPanelにJCheckBoxをはめ込んで返しています。CheckBoxCellRendererクラスのソースは、こちらです。
CheckBoxCellRendererは、DefaultListCellRendererを継承していません。DefaultListCellRendererは描画のためにJLabelを継承して作成されています。チェックボックスを描画するのにJCheckBoxを使うために、それをはめ込めるコンテナクラスを継承したかったためです。JCheckBoxを直接継承しても問題ないと思いますが、とにもかくにもJLabelを継承する必要はないわけです。
JCheckBoxは、JPanelにレイアウトマネージャとしてBorderLayoutを使い、左側に張り込まれるようにします。リストの文字は、getListCellRendererComponentの中で、その都度セットすればいいため、この時点では何も設定していません。
…
public class CheckBoxCellRenderer extends
JPanel implements ListCellRenderer {
JCheckBox jcb;
protected static Border noFocusBorder;
public CheckBoxCellRenderer() {
super();
noFocusBorder
= new EmptyBorder(1, 1, 1, 1);
setOpaque(true);
setBorder(noFocusBorder);
setLayout(
new BorderLayout() );
jcb = new
JCheckBox();
add(
jcb, BorderLayout.WEST );
}
…
|
| CheckBoxCellRendererクラス |
クラス宣言及び、コンストラクタ |
getListCellRendererComponentは、以下のようになっています。このメソッドが呼ばれるごとに、引数に従い、リストの項目の表示状態を組み立てます。JChackBoxへのリストの文字のセットも、この時点で行っています。このとき、セットされる文字は、オブジェクトに対してtoStringメソッドを呼び出して、得られた文字列を使っています。1.1では、これを利用して、構造化されたオブジェクトから、必要な表示文字列を取り出すように実装しています。細かいことですが、覚えておくと便利です。
ViewとModelが結びついているのは、JCheckBoxのsetSelected、setEnabledを呼び出している箇所です。この部分では、CheckBoxListModelから、対応する項目のチェック状態と有効状態を取り出して、JCheckBoxに反映させています。それ以外では、「中略」としている部分では、ボーダーや背景色、フォントに関する処理などを行い、表示の内容を整えています。最終的に、自分自身を返します。
…
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean
isSelected,
boolean
cellHasFocus )
{
CheckBoxListModel
clm = (CheckBoxListModel)list.getModel();
jcb.setText(
value.toString() );
try{
jcb.setSelected(
clm.isSelectedAt( index ) );
jcb.setEnabled(
clm.isEnabledAt( index ) );
}
catch( NoSuchElementException
e ) {}
if( isSelected
) {
jcb.setBackground(
list.getSelectionBackground() );
…// 中略
return
this;
}
…
|
| CheckBoxCellRendererクラス |
getListCellRendererComponentメソッド |
CheckBoxCellRendererクラスでは、もうひとつ、isInCheckBoxというメソッドを宣言しています。これは、ListCheckerクラスの説明をする際に、触れたいと思います。
JListは内部的に、CellRendererPaneという描画のためのオブジェクトを保持しており、これが、返されたComponentを、どんどん位置をずらして描画していきます。CellRendererPaneは、swingの非常に多くのクラスの中で使用されています。JarViewでは、このクラスを利用して、テキストコンポーネントの行番号表示を作成しています。Rendererの作成に慣れてしまえば、同じ形式の描画が繰り返されるような場合の実装に、非常に重宝します。
ListCheckerまで説明するつもりでしたが、思ったよりも長くなってしまいました。今回ここで一旦止めにして、ListCheckerと初期化のシーケンスについては次回にすることにしましょう。

|