---
category: swing
folder: SplitButton
title: JComboBoxのドロップダウンリストで異なる高さのセルを使用する
tags: [JComboBox, JList, ListCellRenderer, PopupMenuListener, JTextArea]
author: aterai
pubdate: 2024-09-30T08:53:40+09:00
description: JComboBoxのセルレンダラとして選択状態用のJCheckBox、複数行文字列用のJTextAreaなどを配置したJPanelを使用し、異なる高さのセルを描画します。
image: https://drive.google.com/uc?id=1tSfYI71idR4Y2i-iH0OxQHtBwLjQghGk
---
* 概要 [#summary]
JComboBoxのセルレンダラとして選択状態用のJCheckBox、複数行文字列用のJTextAreaなどを配置したJPanelを使用し、異なる高さのセルを描画します。
`JComboBox`のセルレンダラとして選択状態用の`JCheckBox`、複数行文字列用の`JTextArea`などを配置した`JPanel`を使用し、異なる高さのセルを描画します。

#download(https://drive.google.com/uc?id=1tSfYI71idR4Y2i-iH0OxQHtBwLjQghGk)

* サンプルコード [#sourcecode]
#code(link){{
JComboBox<ComboItem> combo = new JComboBox<ComboItem>(model) {
  private transient PopupMenuListener listener;

  @Override public void updateUI() {
    removePopupMenuListener(listener);
    super.updateUI();
    setPrototypeDisplayValue(new ComboItem("**********", ""));
    setRenderer(new CheckComboBoxRenderer<>(this));
    // AccessibleContext ac = getAccessibleContext();
    // ComboPopup popup = (ComboPopup) ac.getAccessibleChild(0);
    // JList<?> list = popup.getList();
    // list.setFixedCellHeight(-1);
    listener = new WidePopupMenuListener();
    addPopupMenuListener(listener);
  }
};
}}

* 解説 [#explanation]
- `JComboBox#setPrototypeCellValue(...)`で`JComboBox`本体のサイズを指定
-- ドロップダウンリストで使用する`JList`のセルサイズには影響せず(自動的に`JList#setPrototypeCellValue(...)`は実行されない)、デフォルトの`JList.setFixedCellHeight(-1)`が適用されて各要素のセルレンダラに`getPreferredSize`を設定して`ListUI`でセルの高さが計算される
-- [[JListで異なる高さのセルを使用>Swing/DifferentCellHeight]]
- `JComboBox`に`PopupMenuListener`を追加してドロップダウンリストの幅を`JComboBox`本体より広く設定
-- [[JComboBoxのドロップダウンリスト幅を指定値以上に保つ>Swing/ComboPopupWidth]]
- `JComboBox#setRenderer(...)`で`ListCellRenderer#getListCellRendererComponent(...)`を実装したセルレンダラを設定
-- ドロップダウンリストのセルを描画する場合(`index>=0`)は、選択状態を表示する`JCheckBox`、タイトルを表示する`JLabel`、複数行のテキストを表示する`JTextArea`などを`JPanel`に配置して返す
-- `JComboBox`本体のセルを描画する場合(`index==-1`)は、タイトルを表示する`JLabel`を返す

#code{{
class CheckComboBoxRenderer<E extends ComboItem>
    implements ListCellRenderer<E> {
  private static final Color SELECTED_BGC = new Color(0xC0_E8_FF);
  private final EditorPanel renderer;
  private final JLabel label = new JLabel();
  private final JComboBox<ComboItem> combo;

  protected CheckComboBoxRenderer(JComboBox<ComboItem> combo) {
    this.combo = combo;
    ComboItem proto = Optional
        .ofNullable(combo.getPrototypeDisplayValue())
        .orElseGet(() -> new ComboItem("", ""));
    renderer = new EditorPanel(proto);
  }

  @Override public Component getListCellRendererComponent(
      JList<? extends E> list, E value, int index,
      boolean isSelected, boolean cellHasFocus) {
    Component c;
    if (index >= 0) {
      renderer.setItem(value);
      if (isSelected) {
        renderer.setSelected(true);
        renderer.setOpaque(true);
        renderer.setBackground(SELECTED_BGC);
      } else {
        renderer.setSelected(combo.getSelectedIndex() == index);
        renderer.setOpaque(false);
        renderer.setBackground(Color.WHITE);
      }
      c = renderer;
    } else {
      label.setOpaque(false);
      label.setText(Objects.toString(value, ""));
      c = label;
    }
    return c;
  }
}
}}

* 参考リンク [#reference]
- [[JListで異なる高さのセルを使用>Swing/DifferentCellHeight]]
- [[JComboBoxのドロップダウンリスト幅を指定値以上に保つ>Swing/ComboPopupWidth]]
- [https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/merging-a-pull-request Merging a pull request - GitHub Docs]
-- via: [https://azukiazusa.dev/blog/customizable-select-element/ スタイルをカスタマイズ可能な新しい `<select>` 要素]

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