• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: CheckedComboBox
title: JComboBoxのアイテムとして表示したJCheckBoxを複数選択する
tags: [JComboBox, JCheckBox]
author: aterai
pubdate: 2016-05-23T00:06:37+09:00
description: JComboBoxのアイテムとしてJCheckBoxを表示し、ドロップダウンリストを開いたままこれを複数選択可能に設定します。
image: https://lh3.googleusercontent.com/-I-fHfvCX-IU/V0G4uliNHdI/AAAAAAAAOX0/-746I_MG_jQkqTu1cniGzJqqu3xbc1khACCo/s800/CheckedComboBox.png
hreflang:
    href: https://java-swing-tips.blogspot.com/2016/07/select-multiple-jcheckbox-in-jcombobox.html
    lang: en
---
* 概要 [#c55ce14d]
* 概要 [#summary]
`JComboBox`のアイテムとして`JCheckBox`を表示し、ドロップダウンリストを開いたままこれを複数選択可能に設定します。

#download(https://lh3.googleusercontent.com/-I-fHfvCX-IU/V0G4uliNHdI/AAAAAAAAOX0/-746I_MG_jQkqTu1cniGzJqqu3xbc1khACCo/s800/CheckedComboBox.png)

* サンプルコード [#aa48ed07]
* サンプルコード [#sourcecode]
#code(link){{
class CheckedComboBox<E extends CheckableItem> extends JComboBox<E> {
  private boolean keepOpen;
  private transient ActionListener listener;

  protected CheckedComboBox() {
    super();
  }

  protected CheckedComboBox(ComboBoxModel<E> aModel) {
    super(aModel);
  }

  protected CheckedComboBox(E[] m) {
    super(m);
  }

  @Override public Dimension getPreferredSize() {
    return new Dimension(200, 20);
  }

  @Override public void updateUI() {
    setRenderer(null);
    removeActionListener(listener);
    super.updateUI();
    listener = e -> {
      if (e.getModifiers() == InputEvent.BUTTON1_MASK) {
      if ((e.getModifiers() & AWTEvent.MOUSE_EVENT_MASK) != 0) {
        updateItem(getSelectedIndex());
        keepOpen = true;
      }
    };
    setRenderer(new CheckBoxCellRenderer<CheckableItem>());
    addActionListener(listener);
    getInputMap(JComponent.WHEN_FOCUSED).put(
        KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "checkbox-select");
    getActionMap().put("checkbox-select", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        Accessible a = getAccessibleContext().getAccessibleChild(0);
        if (a instanceof BasicComboPopup) {
          BasicComboPopup pop = (BasicComboPopup) a;
          updateItem(pop.getList().getSelectedIndex());
        }
      }
    });
  }

  private void updateItem(int index) {
    if (isPopupVisible()) {
      E item = getItemAt(index);
      item.selected ^= true;
      removeItemAt(index);
      insertItemAt(item, index);
      setSelectedIndex(-1);
      setSelectedItem(item);
    }
  }

  @Override public void setPopupVisible(boolean v) {
    if (keepOpen) {
      keepOpen = false;
    } else {
      super.setPopupVisible(v);
    }
  }
}
}}

* 解説 [#n0420ae7]
* 解説 [#explanation]
- タイトルと選択状態をもつアイテムオブジェクト`CheckableItem`を作成し、そのモデルとして`ComboBoxModel<CheckableItem>`を作成
- `CheckBoxCellRenderer<E extends CheckableItem>`を作成し、チェック状態を表示
-- `JComboBox`本体: レンダラーに`JLabel`を使用し、選択されている`CheckableItem`のタイトルを収集してカンマで結合して一覧表示
-- ドロップダウンリスト: レンダラーに`JCheckBox`を使用し、チェック状態とタイトルを表示
- `JComboBox`に`ActionListener`を追加し、マウスの左クリックかつドロップダウンリストが表示されている場合は、選択されたアイテムのチェック状態を反転
-- この場合は、ドロップダウンリストを閉じないように、`JComboBox#setPopupVisible(...)`をオーバーライド
- KBD{Space}キーでアイテムが選択された場合は、`BasicComboPopup`から`JList`を取得し、その選択アイテムを取得する
-- この場合、`JComboBox#getSelectedIndex()`などを使用すると、ハイライト(`cellHasFocus`)されているアイテムではなく、選択状態(`isSelected`)のアイテムが取得される
-- この場合は、ドロップダウンリストを閉じないように`JComboBox#setPopupVisible(...)`をオーバーライド
- KBD{Space}キーでアイテムが選択された場合は、`BasicComboPopup`から`JList`を取得してその選択アイテムを取得する
-- この場合、`JComboBox#getSelectedIndex()`などを使用するとハイライト(`cellHasFocus`)されているアイテムではなく選択状態(`isSelected`)のアイテムが取得される

//* 参考リンク
* コメント [#u1b09f05]
* 参考リンク [#reference]
- [[JComboBoxのドロップダウンリスト中にあるアイテムの状態を更新する>Swing/UpdateComboBoxItem]]

* コメント [#comment]
#comment
#comment