概要

JComboBoxのアイテムとしてJCheckBoxを表示し、ドロップダウンリストを開いたままこれを複数選択可能に設定します。

サンプルコード

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) {
        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);
      setSelectedItem(item);
    }
  }
  @Override public void setPopupVisible(boolean v) {
    if (keepOpen) {
      keepOpen = false;
    } else {
      super.setPopupVisible(v);
    }
  }
}
view all

解説

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

コメント