getListCellRendererComponentメソッド

広告

ListCellRendererインターフェースを実装するにに必要なメソッドである「getListCellRendererComponent」メソッドについて確認していきます。

Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)

指定された値を表示するように設定されたコンポーネントを返します。次に、そ
のコンポーネントの paint メソッドが呼び出されて、セルを「描画」します。
リストセルのサイズが固定されていないため、リストの寸法を計算する必要があ
る場合には、このメソッドが呼び出されて、getPreferredSize を呼び出せるコ
ンポーネントを生成します。

パラメータ:
  list - ペイントしている JList
  value - list.getModel().getElementAt(index) によって返される値
  index - セルのインデックス
  isSelected - 指定されたセルが選択された場合は true
  cellHasFocus - 指定されたセルにフォーカスがある場合は true 
戻り値:
  指定された値を描画する paint() メソッドがあるコンポーネント

コンボボックスでは1つ1つの項目が表示されようとする時に、実際に表示するコンポーネントを取得するためにこのメソッドを呼び出します。レンダラクラスの中では、このメソッド内で必要なコンポーネントを作成し戻り値を呼び出し元に返す必要があります。

コンボボックスで各項目を単に文字列として表示するのであればJLabelクラスのオブジェクトを作成して戻り値として設定するのが一般的です。

そこでよく使われる記述方法が、getListCellRendererComponentメソッドを定義するクラスをコンポーネントのサブクラスとして定義し、getListCellRendererComponentメソッドも戻り値は自分自身である「this」を記述する方法です。

class MyCellRenderer extends JLabel implements ListCellRenderer {
  public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

    return this;
  }
}

この場合は「getListCellRendererComponent」メソッドはJLabelクラスのオブジェクトを返すことになります。コンボボックス側では1つ1つの項目を表示する時に「getListCellRendererComponent」メソッドから返されたJLabelクラスのオブジェクトをコンボボックスに表示します。

呼び出し元のオブジェクトの判別

上記ではラベルに表示される文字列などを何も設定していません。その為、コンボボックスのどの項目の表示の時にメソッドが呼び出されても何も文字列が設定されていないJLabelクラスのオブジェクトが帰ってくることになります。そこでコンボボックスのどの項目を表示しようとしている時にこのメソッドが呼び出されたのかを取得し、項目毎に適切な設定してから呼び出し元にオブジェクトを返す必要があります。

2番目の引数で渡されてくるObject型の値は、コンボボックスで表示をしようとしている項目のオブジェクトが渡されてきます。そこで次のように記述することで適切な文字列が設定されたJLabelクラスのオブジェクトを返すことが出来るようになります。

class MyCellRenderer extends JLabel implements ListCellRenderer {
  public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

    setText(value.toString());

    return this;
  }
}

コンボボックスに登録されているデータがString型の値ばかりと分かっていれば、単にString型にキャストしてラベルに表示される文字列に設定しても構いません。

例えば次のように記述するとコンボボックスに登録されている各項目の値を全て大文字に変換して表示することができます。

class MyCellRenderer extends JLabel implements ListCellRenderer {
  public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

    String data = value.toString();
    setText(data.toUpperCase());

    return this;
  }
}

選択項目かどうかの判別

コンボボックスのドロップダウンリストが表示された時に、どの項目にマウスが乗っているのかを判別し区別が付くように表示方法を変更する必要があります。

4番目の引数で渡されてくるboolean型の値は、コンボボックスで表示をしようとしている項目が現在選択状態なのかどうかを表すboolean型の値が渡されてきます。選択状態と非選択状態にあるのが区別が付くように選択状態の項目の場合には前景色や背景色を変更して設定するようにします。

class MyCellRenderer extends JLabel implements ListCellRenderer {
  public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

    String data = value.toString();
    setText(data.toUpperCase());

    setOpaque(true);

    if (isSelected){
      setForeground(Color.white);
      setBackground(Color.black);
    }else{
      setForeground(Color.black);
      setBackground(Color.white);
    }

    return this;
  }
}

上記の場合、選択されていない項目は背景色が白で前景色が黒、選択されている項目は背景色が黒で前景色が白として設定されます。

注意点としては「isSelected」の値を使って設定を変更する時は「true」の場合と「false」の場合の両方の処理を必ず記述して下さい。なぜならば呼び出し元に戻されるJLabelのオブジェクトは1つのオブジェクトを共有しているため、設定が行われない場合には前に行った設定の結果がそのまま残っているからです。例えば「true」の場合だけの処理を記述していると、一度「true」の処理が行われるとその後で呼び出された場合には「true」の時に行った設定が残ってしまっています。その為、必ず「false」の場合の処理も合わせて記述するようにして下さい。

なお「setOpaque(true)」のような処理は一度行っておけばいいので、このような処理はコンストラクタに記述します。

class MyCellRenderer extends JLabel implements ListCellRenderer {
  MyCellRenderer(){
    setOpaque(true);
  }

  public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

    String data = value.toString();
    setText(data.toUpperCase());

    if (isSelected){
      setForeground(Color.white);
      setBackground(Color.black);
    }else{
      setForeground(Color.black);
      setBackground(Color.white);
    }

    return this;
  }
}

サンプルプログラム

では簡単なサンプルを作成して試してみます。

JComboBoxTest17.java

import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.Component;

public class JComboBoxTest17 extends JFrame{

  public static void main(String[] args){
    JComboBoxTest17 frame = new JComboBoxTest17();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(10, 10, 300, 200);
    frame.setTitle("タイトル");
    frame.setVisible(true);
  }

  JComboBoxTest17(){
    String[] combodata = {"Swing", "Java2D", "Java3D", "JavaMail"};
    DefaultComboBoxModel model = new DefaultComboBoxModel(combodata);

    JComboBox combo = new JComboBox(model);
    combo.setPreferredSize(new Dimension(140, 30));

    MyCellRenderer renderer = new MyCellRenderer();
    combo.setRenderer(renderer);

    JPanel p = new JPanel();
    p.add(combo);

    getContentPane().add(p, BorderLayout.CENTER);
  }

  class MyCellRenderer extends JLabel implements ListCellRenderer{
    MyCellRenderer(){
      setOpaque(true);
    }

    public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus){

      String data = value.toString();
      setText(data.toUpperCase());

      if (isSelected){
        setForeground(Color.white);
        setBackground(Color.black);
      }else{
        setForeground(Color.black);
        setBackground(Color.white);
      }

      return this;
    }
  }
}

上記をコンパイルした後で実行すると次のように表示されます。

JComboBoxでレンダラ定義して設定する

ドロップダウンリストを表示すると、各項目が全て大文字となっており、マウスで選択されている項目とされていない項目によって表示方法が変わっていることが確認できます。

JComboBoxでレンダラ定義して設定する

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。