はじめに
今回は、各種の情報を保持して利用するコンポーネントについて考えてみます。コンポーネントの中には、さまざまな情報を表示するためのものがあります。比較的単純なものとしてはJComboBoxやJList、複雑なデータ構造を持つものとしてはJTreeやJTableなどがあります。これらは「セル」と呼ばれる、保持している値を表示するための部品を組み合わせて構成されています。
これらのコンポーネントは、実は1つのクラスだけでできているのではありません。コンポーネントの表示は「レンダラー」と呼ばれるオブジェクトが行い、保持するデータの管理は「モデル」というオブジェクトが行っています。このようにいくつかのオブジェクトによってコンポーネントは構成されているのです。
ここでは、JListを例に、レンダラーとモデルについて考えてみましょう。
対象読者
- Javaの基本機能は一通り覚えた、というビギナーを卒業しかけている人。
- Swingはマスターした? といわれると、ちょっと自信がない人。
- これからはクライアントサイドが注目されると信じる人。
ListCellRendererとリスト表示コンポーネント
レンダラーは、「セル」の表示を行うのに用いられるクラスです。これはコンポーネントの種類に応じて複数のものが用意されています。コンポーネントによっては、さまざまな状況に応じて表示が変化したりするので、それらに対応したレンダラーが複数用意されています。
ここでは、比較的構造のシンプルな「JList」を使ってレンダラーの基本的な使い方を説明しましょう。JListは、コンポーネントの中にいくつかの項目が一覧表示されます。この1つ1つの項目が「セル」なのです。JListでは、セルの表示はjavax.swing.DefaultListCellRenderer
クラスがレンダラーとして組み込まれています。このDefaultListCellRenderer
は、javax.swing.ListCellRenderer
というインターフェイスをimplementsして定義されています。JListのレンダラーは、このListCellRenderer
をimplementsしたクラスとして定義する必要があります。
ListCellRenderer
は、1つのメソッドだけ用意されている非常にシンプルなインターフェイスです。これは次のように定義されています。
public interface ListCellRenderer { public Component getListCellRendererComponent( JList list,Object object,int index,boolean isSelected, boolean hasFocus); }
getListCellRendererComponent
というメソッドが、レンダラーオブジェクトを作成し返す働きをするものです。このメソッドでは、引数に渡された情報を元に、セルに表示するComponentを作成して返します。要するにレンダラーの正体とは、「必要に応じてセルに表示するComponentを作成して返すもの」だったのです。
メソッドで渡される引数には、次のような値が収められています。これらの値を元にComponentを作成するわけです。
引数 | 説明 |
JList list | レンダラーを要求してきたJList |
Object object | レンダラーを表示するセルの値オブジェクト |
int index | セルのインデックス番号 |
boolean isSelected | 選択されているか否か |
boolean hasFocus | フォーカスがあるか否か |
セルに表示される値は、Object
である点に注意しましょう。String
ではありません。JListでは、値はString
である必要はないのです。
色の値を視覚的に表示するレンダラー
では、実際に簡単なJList用レンダラーを作成してみましょう。ここでは、テキスト以外のオブジェクトを値に保管し表示する例として、Color
の値を視覚的に表示するレンダラークラスを作成してみましょう。
package jp.codezine; import java.awt.*; import javax.swing.*; public class SampleApp extends JFrame { private static final long serialVersionUID = 1L; JLabel label; JList list; public SampleApp(){ this.setSize(new Dimension(250,250)); label = new JLabel("JList Sample"); this.add(label,BorderLayout.NORTH); list = this.createList(); this.add(new JScrollPane(list),BorderLayout.CENTER); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } // JListの生成 public JList createList(){ MyColor[] array = {new MyColor(255,255,255), new MyColor(255,0,0), new MyColor(0,255,0), new MyColor(0,0,255), new MyColor(255,255,0), new MyColor(0,255,255), new MyColor(255,0,255), new MyColor(0,0,0)}; JList list = new JList(array); // ColorRendererをレンダラーに設定する list.setCellRenderer(new ColorRenderer()); return list; } public static void main(String[] args) { new SampleApp().setVisible(true); } } class ColorRenderer implements ListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object object, int index, boolean isSelected, boolean hasFocus) { JLabel label = new JLabel(); try { Color c = (Color)object; label.setText(c.toString()); label.setOpaque(true); label.setFont(new Font("Serif",Font.BOLD,16)); label.setBackground(c); int n = c.getRed() + c.getGreen() + c.getBlue(); // 選択されているかどうかで処理を分ける if (isSelected){ label.setForeground(c); } else { label.setForeground(n > 384 ? Color.BLACK : Color.WHITE); } } catch (ClassCastException e) { e.printStackTrace(); } return label; } } class MyColor extends Color { private static final long serialVersionUID = 1L; public MyColor(int r,int g,int b) { super(r, g, b); } @Override public String toString() { return "[" + this.getRed() + ":" + this.getGreen() + ":" + this.getBlue() + "]"; } }