WisdomSoft - for your serial experiences.

6.4 コンボボックス

複数項目をドロップダウンリストに表示するコンボボックスを JComboBox クラスを用いて作成します。

6.4.1 展開可能なリスト

コンボボックスは単一の項目を選択するドロップダウンリストを提供する編集可能なリストコンポーネントです。項目を列挙するコンポーネントなので多くの点でリストに似ていますが、単一の項目しか選択できないことや、必要に応じて項目を編集するという部分でリストとは異なります。

コンボボックスは javax.swing.JComboBox クラスを使って生成します。

javax.swing.JComboBox クラス
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
                    |
                    +--javax.swing.JComboBox
public class JComboBox extends JComponent
	implements ItemSelectable, ListDataListener, ActionListener, Accessible

コンボボックスもデータをドロップダウンリストに列挙するので、リスト同様に Object 型の配列や Vector オブジェクトをコンストラクタから受けることができます。また、リストが内部で項目を管理する ListModel オブジェクトを保有していたように、コンボボックスもまた ComboBoxModel オブジェクトをデータモデルとして保有しています。

表1 JComboBox クラスのコンストラクタと選択に関するメソッド
コンストラクタ 解説
public JComboBox() デフォルトのデータモデルでコンボボックスを構築する。
public JComboBox(Object[] items) 指定された配列に要素を格納するコンボボックスを構築する。
public JComboBox(Vector items) 指定された Vector に要素を格納するコンボボックスを構築する。
public JComboBox(ComboBoxModel aModel) 項目を既存の ComboBoxModel から取得するコンボボックスを構築する。
メソッド
public void addActionListener(ActionListener l) 選択、または編集を終了すると呼び出されるリスナを追加する。
public void removeActionListener(ActionListener l) ActionListener を削除する。
public ActionListener[] getActionListeners() 設定されているすべての ActionListener の配列を返す。
public void addPopupMenuListener(PopupMenuListener l) ポップアップイベントで呼び出されるリスナを追加する。
public void removePopupMenuListener(PopupMenuListener l) PopupMenuListener を削除する。
public PopupMenuListener[] getPopupMenuListeners() 設定されているすべての PopupMenuListener の配列を返す。
public void addItemListener(ItemListener aListener) 選択した項目が変更されると呼び出されるリスナを追加する。
public void removeItemListener(ItemListener aListener) ItemListener を削除する。
public ItemListener[] getItemListeners() 設定されているすべての ItemListener の配列を返す。
public void addItem(Object anObject) 項目を項目リストに追加する。
public void insertItemAt(Object anObject,int index) 項目を項目リストのインデックスで指定された位置に追加する。
public void removeItem(Object anObject) 項目を項目リストから削除する。
public void removeItemAt(int anIndex) anIndex 位置の項目を削除する。
public void removeAllItems() 項目リストからすべての項目を削除する。
public void showPopup() コンボボックスにポップアップウィンドウを表示させる。
public void hidePopup() コンボボックスにポップアップウィンドウを閉じる。
public void setSelectedIndex(int anIndex) anIndex にある項目を選択する。
public int getSelectedIndex() 現在選択されている項目のインデックスを返す。
public void setSelectedItem(Object anObject) 指定した項目を選択する。
public Object getSelectedItem() 現在選択されている項目を返す。

コンボボックスはデフォルトでは編集不可能になってますが、必要に応じて項目を編集することができるコンボボックスを設定することもできます。項目が選択されたり、編集が終了するとコンボボックスは ActionListener オブジェクトのメソッドを呼び出し、項目の選択が変更した時点では ItemListener オブジェクトを呼び出します。他の項目を選択したときの動作は ItemListener が先に呼び出され、その後 ActionListener の順番となります。

javax.swing.event.PopupMenuListener インタフェースは、クリックなどの動作で項目を列挙するリストが展開するポップアップ型コンポーネントが通知するイベントを処理します。このインタフェースを実装すれば、コンボボックスのリストが表示されたり閉じられたりした瞬間を捉えることができます。このインタフェースには次のメソッドが宣言されてます。

PopupMenuListener インターフェイス popupMenuWillBecomeVisible() メソッド
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
PopupMenuListener インターフェイス popupMenuWillBecomeInvisible() メソッド
public void popupMenuWillBecomeInvisible(PopupMenuEvent e)nuEvent e)
PopupMenuListener インターフェイス popupMenuCanceled() メソッド
public void popupMenuCanceled(PopupMenuEvent e)

パラメータで受け取る PopupMenuEvent クラスは EventObject クラスを継承するイベント情報クラスですが、ポップアップに関する情報は存在しないので、このクラスは新しいメソッドを宣言してません。JComboBox クラスの showPopup() メソッドhidePopup() メソッドを呼び出せば、プログラムかリストを開閉することができることにも注目してください。

コード1
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class Test implements ActionListener, PopupMenuListener, ItemListener {
	public static void main(String args[]) {
		Test listener = new Test();

		JComboBox list = new JComboBox(args);
		list.addActionListener(listener);
		list.addItemListener(listener);
		list.addPopupMenuListener(listener);

		JFrame win = new JFrame();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.getContentPane().setLayout(new FlowLayout());
		win.getContentPane().add(list);
		win.show();
	}

	public void actionPerformed(ActionEvent e) {
		System.out.println("Action performed.");
	}

	public void itemStateChanged(ItemEvent e) {
		System.out.println("Item state changed.");
	}

	public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
		System.out.println("Popup menu will become visible.");
	}
	public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
		System.out.println("Popup menu will become invisible.");
	}
	public void popupMenuCanceled(PopupMenuEvent e) {
		System.out.println("Popup menu canceled.");
	}
}
実行結果
コード1 実行結果

コード1は、プログラム起動時に指定した引数を項目として表示するコンボボックスを表示します。このプログラムではコンボボックスが通知する主なイベントを実装し、イベントが発生すると標準出力にメソッドが起動されたことをアピールします。

6.4.2 項目の制御

JComboBox クラスのメソッドから新しい項目を追加するなど、ある程度項目を制御することは可能です。しかし、項目を特定の型に制限したり、動的に項目を増やしたり、削除したりするには、やはり項目を管理する javax.swing.ComboBoxModel インタフェースを使ったほうが便利でしょう。このクラスは ListBoxModel を継承しているので、基本的な考え方は ListBoxModel クラスと同じです。コンボボックスの場合は、選択されている項目を制御するメソッドが追加されています。

表2 ComboBoxModel インタフェースのメソッド
メソッド 解説
public void setSelectedItem(Object anItem) 指定した項目を選択する。
public Object getSelectedItem() 現在選択されている項目を返す。

ComboBoxModel のデフォルトの実装は javax.swing.DefaultComboBoxModel クラスです。このクラスは Object 型の配列や Vector オブジェクトを使って項目を初期化できるほかに、動的に項目を追加したり、削除したりすることができます。

javax.swing.DefaultComboBoxModel クラス
java.lang.Object
  |
  +--javax.swing.AbstractListModel
        |
        +--javax.swing.DefaultComboBoxModel
public class DefaultComboBoxModel extends AbstractListModel implements MutableComboBoxModel, Serializable

DefaultComboBoxModel が実装している javax.swing.MutableComboBoxModel インタフェースは ComboBoxModel を継承する動的に項目を設定できるコンボボックスのモデルであることを保証します。DefaultComboBoxModel は、これらのすべての機能を提供しているのです。

表3 MutableComboBoxModel インタフェースのメソッド
メソッド 解説
public void addElement(Object obj) モデルの末尾に項目を追加する。
public void insertElementAt(Object obj, int index) 特定のインデックスに項目を追加する。
public void removeElement(Object obj) モデルから項目を削除する。
public void removeElementAt(int index) 特定のインデックスから項目を削除する。

コンボボックスのデータモデルが MutableComboBoxModel を実装しているのであれば、コンボボックスにはデータを可変的に追加したり削除することができることを意味します。逆に、独自にモデルを実装するのであれば、データモデルが動的か静的かで ComboBoxModel を実装するのか、MutableComboBoxModel を実装するのかを判断すると良いでしょう。

コンボボックスにデータモデルを設定するには、コンストラクタのほかに setModel() メソッドがあります。現在、コンボボックスが項目を管理するために利用しているモデルを取得するには getModel() メソッドを使います。

JComboBox クラス setModel() メソッド
public void setModel(ComboBoxModel aModel)
JComboBox クラス getModel() メソッド
public ComboBoxModel getModel()

独自に実装した ComboBoxModel を採用したい場合は setModel() メソッドやコンストラクタからオブジェクトを設定すると良いでしょう。

コード2
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test extends JFrame implements ActionListener {
	public static void main(String args[]) {
		JFrame win = new Test();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.show();
	}

	private JComboBox list = new JComboBox();
	private JButton addButton = new JButton("Add Item");
	private JButton removeButton = new JButton("Remove Item");
	public Test() {
		addButton.addActionListener(this);
		removeButton.addActionListener(this);

		getContentPane().setLayout(new FlowLayout());
		getContentPane().add(addButton);
		getContentPane().add(removeButton);
		getContentPane().add(list);
	}

	public void actionPerformed(ActionEvent e) {
		ComboBoxModel cModel = list.getModel();
		MutableComboBoxModel mcModel = null;
		if (cModel instanceof MutableComboBoxModel) {
			mcModel = (MutableComboBoxModel)cModel;
		}
		else return;

		if (e.getSource() == addButton) {
			mcModel.addElement("Item" + cModel.getSize());
		}
		else if (e.getSource() == removeButton) {
			if (cModel.getSize() == 0) return;
			mcModel.removeElementAt(list.getSelectedIndex());
		}
	}
}
実行結果
コード2 実行結果

コード 06_04_01 は ComboBoxModel を利用して動的にコンボボックスの項目を追加したり、削除したりすることができるプログラムです。"Add Item" ボタンを押すと項目が追加され "Remove Item" ボタンを押すと現在選択されているボタンが削除されます。

ボタンが押されると、まず getModel() メソッドを使ってコンボボックスに設定されているデータモデルを取得します。次に instanceof 演算子でこのモデルが可変であるかどうかを調べ MutableComboBoxModel を実装しているようであればキャストします。デフォルトのモデルである DefaultComboBoxModel クラスは MutableComboBoxModel を採用していますが、独自の実装であれば必ずしも MutableComboBoxModel を実装しているとは限りません。

無事にキャストできれば、後はイベントオブジェクトの getSource() メソッドでイベントを発生させたオブジェクトを調べます。このプログラムでは 2 つのボタンが同じ ActionListener を共有しているので、どちらのボタンが押されたのかを識別する必要があるためです。

因みに、コンボボックスの項目もセルレンダラを保有しているため、項目の描画を拡張することができます。コンボボックスのセルを描画するのはリストと同じ ListCellRenderer オブジェクトなので、拡張方法はリストと同じです。レンダラを設定するには setRenderer() メソッドを、取得するには getRenderer() メソッドを使います。

JComboBox クラス setRenderer() メソッド
public void setRenderer(ListCellRenderer aRenderer)
JComboBox クラス getRenderer() メソッド
public ListCellRenderer getRenderer()

レンダラを独自に実装すれば、アイコンやイメージを項目として描画することができるようになるでしょう。

6.4.3 編集可能コンボボックス

あまり編集を目的としてコンボボックスが利用されることはないと思われますが、コンボボックスは項目を編集する機能があります。デフォルトでは編集機能は無効とされてますが、JComboBox クラスの setEditable() メソッドを使って切り替えることが可能です。現在、項目を編集することができるかどうかを調べるには isEditable() メソッドを使います。

JComboBox クラス setEditable() メソッド
public void setEditable(boolean aFlag)
JComboBox クラス isEditable() メソッド
public boolean isEditable()

setEditable() メソッドに true を設定すれば、コンボボックスは編集可能となります。このとき編集領域に表示されるのは Swing のテキスト入力コンポーネントです。つまり、項目のテキストを編集することができるのです。

しかし、レンダラやデータモデルを拡張してイメージを列挙している場合、テキストを編集するのは奇妙です。コンボボックスがイメージを扱っているのであれば、テキストではなくイメージを編集する手段を提供するべきかもしれません。すばらしいことに、Swing はエディタを独自に実装する手段を提供してます。

isEditable() が true の状態であれば、コンボボックスは自らに設定されている javax.swing.ComboBoxEditor インタフェースを実装するオブジェクトを使ってエディタを表示します。このインタフェースは編集対象のオブジェクトと、編集を行うコンポーネント、そして編集の終了を通知するイベントを提供します。

表4 ComboBoxEditor インタフェースのメソッド
メソッド 解説
public void addActionListener(ActionListener l) アクションリスナーを追加する。
public void removeActionListener(ActionListener l) アクションリスナーを削除する。
public void selectAll() エディタに編集の開始とすべての選択を要求する。
public void setItem(Object anObject) 編集項目を設定します。必要に応じて編集を取り消する。
public Object getItem() 編集項目を返す。
public Component getEditorComponent() エディタのツリー階層に追加するコンポーネントを返す。

Swing のデフォルトの実装は javax.swing.plaf.basic.BasicComboBoxEditor クラスです。 このクラスでは、Swing のテキスト入力フィールドをコンボボックスのエディタとして返します。

ただし、コンボボックスの編集機能はあくまで簡易機能であり、本格的な編集作業を行う必要があれば、専用のコンポーネントを開発したほうがユーザーにとっては使いやすいでしょう。

コード3
import java.awt.*;
import javax.swing.*;

public class Test {
	public static void main(String args[]) {
		JComboBox list = new JComboBox(args);
		list.setEditable(true);

		JFrame win = new JFrame();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.getContentPane().add(list , BorderLayout.NORTH);
		win.show();
	}
}
実行結果
コード3 実行結果

コード 06_04_02 は編集可能なコンボボックスを表示してます。このコンボボックスが表示しているテキスト入力コンポーネントは Swing の JTextField と言うコンポーネントです。テキスト入力について、詳しくは第8章で解説します。