リストの項目にJCheckBoxを表示する

広告

次にJListの項目にJCheckBoxを表示させて見ましょう。(ここで書いた方法が一番いいかどうかは分かりません。取りあえず動くようにはなったので記載しておきます)。

まず ListCellRenderer をJCheckBoxを継承して作成します。

import javax.swing.*;
import java.awt.*;

public class JListSample extends JFrame{
  protected JList list;
  protected DefaultListModel model;

  public static void main(String[] args){
    JListSample test = new JListSample("JListSample");

    /* 終了処理を変更 */
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    test.setBounds( 10, 10, 250, 130);
    test.setVisible(true);
  }

  JListSample(String title){
    setTitle(title);

    String[] initData = {"Blue", "Green", "Red", "Whit", "Black"};
    list = new JList(initData);

    /* CellRendererを設定する */
    MyCellRenderer renderer = new MyCellRenderer();
    list.setCellRenderer(renderer);

    JScrollPane sp = new JScrollPane();
    sp.getViewport().setView(list);
    sp.setPreferredSize(new Dimension(200, 80));

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

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

  class MyCellRenderer extends JCheckBox implements ListCellRenderer{
    public MyCellRenderer() {
    }

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

      setText(value.toString());

      return this;
    }
  }
}

実行結果は下記のようになります。

リストの項目にJCheckBoxを表示する

一応、JCheckBoxが表示されます。ただ、このままではチェックボックスを選択することができません。最初はgetListCellRendererComponentメソッド内で、項目が選択されたら変更しようとしたのですが、実際に試してみると分かるのですけど画面表示が何故か滅茶苦茶になります。

その為、項目の値は"String"型で、表示の仕方だけ"JCheckBox"にするのではなく、JListに入れる項目の値を"JCheckBox"にしてみます。

まずはJListの項目をJCheckBoxの値に変更してみます。

import javax.swing.*;
import java.awt.*;

public class JListSample extends JFrame{
  protected JList list;
  protected DefaultListModel model;

  public static void main(String[] args){
    JListSample test = new JListSample("JListSample");

    /* 終了処理を変更 */
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    test.setBounds( 10, 10, 250, 130);
    test.setVisible(true);
  }

  JListSample(String title){
    setTitle(title);

    model = new DefaultListModel();
    String[] initData = {"Blue", "Green", "Red", "Whit", "Black"};
    for (int i = 0 ; i < initData.length ; i++){
      /* 指定した文字列を持つチェックボックスをJListに登録する */
      model.addElement(new JCheckBox(initData[i]));
    }
    list = new JList(model);

    /* CellRendererを設定する */
    MyCellRenderer renderer = new MyCellRenderer();
    list.setCellRenderer(renderer);

    JScrollPane sp = new JScrollPane();
    sp.getViewport().setView(list);
    sp.setPreferredSize(new Dimension(200, 80));

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

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

  class MyCellRenderer extends JCheckBox implements ListCellRenderer{
    public MyCellRenderer() {
    }

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

      /* 項目の値を読み出して改めて表示する */
      JCheckBox checkBox = (JCheckBox)value;
      setText(checkBox.getText());

      return this;
    }
  }
}

実行結果は下記のようになります。

リストの項目にJCheckBoxを表示する

見た目は変わりがありませんが、リストに登録されている項目は文字列ではなくJCheckBoxオブジェクトになります。"getListCellRendererComponent"メソッドの中身も変わっているので注意してください。

次にJListにMouseListenerをセットして、JList上でマウスがクリックした時の座標を読み出し、その座標からクリックされたJListの項目のIndex番号を調べます。そして、その項目が現在選択されていれば選択状態を外し、選択されていなければ選択状態にするようにいたします。

ここで、座標から該当の項目Index番号を調べるために、JListクラスの"locationToIndex"メソッドを使っています。

JList の座標上の点をその位置にあるセルのインデックスに変換します。セル
が実際にその位置を含むかどうかを判定するには、このメソッドと 
getCellBounds を組み合わせて使用します。モデルが空の場合は、-1 を返し
ます。

パラメータ:
  location - JList に関連したセルの座標 
戻り値:
  整数 -- 指定位置のセルのインデックス、または -1

では、ここまでのサンプルを見てください。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class JListSample extends JFrame implements MouseListener{
  protected JList list;
  protected DefaultListModel model;

  public static void main(String[] args){
    JListSample test = new JListSample("JListSample");

    /* 終了処理を変更 */
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    test.setBounds( 10, 10, 250, 130);
    test.setVisible(true);
  }

  JListSample(String title){
    setTitle(title);

    model = new DefaultListModel();
    String[] initData = {"Blue", "Green", "Red", "Whit", "Black"};
    for (int i = 0 ; i < initData.length ; i++){
      /* 指定した文字列を持つチェックボックスをJListに登録する */
      model.addElement(new JCheckBox(initData[i]));
    }
    list = new JList(model);

    /* CellRendererを設定する */
    MyCellRenderer renderer = new MyCellRenderer();
    list.setCellRenderer(renderer);

    /* MouseListenerをセットする */
    list.addMouseListener(this);

    JScrollPane sp = new JScrollPane();
    sp.getViewport().setView(list);
    sp.setPreferredSize(new Dimension(200, 80));

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

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

  class MyCellRenderer extends JCheckBox implements ListCellRenderer{
    public MyCellRenderer() {
    }

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

      /* 項目の値を読み出して改めて表示する */
      JCheckBox checkBox = (JCheckBox)value;
      setText(checkBox.getText());

      setSelected(checkBox.isSelected());

      return this;
    }
  }

  public void mouseClicked(MouseEvent e){
    /* クリックされた座標からIndex番号を取り出す */
    Point p = e.getPoint();
    int index = list.locationToIndex(p);

    JCheckBox checkBox = (JCheckBox)model.getElementAt(index);
    if (checkBox.isSelected()){
      checkBox.setSelected(false);
    }else{
      checkBox.setSelected(true);
    }
  }

  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mousePressed(MouseEvent e){}
  public void mouseReleased(MouseEvent e){}
}

実行結果は下記のようになります。

リストの項目にJCheckBoxを表示する

上記のサンプルではgetListCellRendererComponentメソッド内でも、元の項目の値が選択されていたら、表示上も選択するように変更していますので注意して下さい。

一応チェックしたりできるようになったのですが、クリックしても表示上変わらなかったりと挙動がかなり怪しいです。元のデータの値を調べてみるとちゃんとクリックした結果が反映されていましたので、恐らくJCheckBoxの選択/非選択が変更された時に、再描画がうまく行われていないのではないかと思います。

細かい原因が分からないので、取りあえずmouseClickedメソッドの最後でrepaintを呼ぶようにしてみました。下記のサンプルが最終的な結果となります。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class JListSample extends JFrame implements MouseListener{
  protected JList list;
  protected DefaultListModel model;

  public static void main(String[] args){
    JListSample test = new JListSample("JListSample");

    /* 終了処理を変更 */
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    test.setBounds( 10, 10, 250, 130);
    test.setVisible(true);
  }

  JListSample(String title){
    setTitle(title);

    model = new DefaultListModel();
    String[] initData = {"Blue", "Green", "Red", "Whit", "Black"};
    for (int i = 0 ; i < initData.length ; i++){
      /* 指定した文字列を持つチェックボックスをJListに登録する */
      model.addElement(new JCheckBox(initData[i]));
    }
    list = new JList(model);

    /* CellRendererを設定する */
    MyCellRenderer renderer = new MyCellRenderer();
    list.setCellRenderer(renderer);

    /* MouseListenerをセットする */
    list.addMouseListener(this);

    JScrollPane sp = new JScrollPane();
    sp.getViewport().setView(list);
    sp.setPreferredSize(new Dimension(200, 80));

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

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

  class MyCellRenderer extends JCheckBox implements ListCellRenderer{
    public MyCellRenderer() {
    }

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

      /* 項目の値を読み出して改めて表示する */
      JCheckBox checkBox = (JCheckBox)value;
      setText(checkBox.getText());

      setSelected(checkBox.isSelected());

      return this;
    }
  }

  public void mouseClicked(MouseEvent e){
    /* クリックされた座標からIndex番号を取り出す */
    Point p = e.getPoint();
    int index = list.locationToIndex(p);

    JCheckBox checkBox = (JCheckBox)model.getElementAt(index);
    if (checkBox.isSelected()){
      checkBox.setSelected(false);
    }else{
      checkBox.setSelected(true);
    }

    /* 再描画してみる */
    list.repaint();
  }

  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mousePressed(MouseEvent e){}
  public void mouseReleased(MouseEvent e){}
}

実行結果は下記のようになります。

リストの項目にJCheckBoxを表示する

今度はうまくいきました。一応こういう形で行わば作ることはできますけど、もし他にうまい方法があれば、改めて更新したいと思います。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)