---
category: swing
folder: ComboBoxOverflowToolTips
title: JComboBoxで文字列が溢れる場合はJToolTipを表示可能にする
tags: [JComboBox, JToolTip, ListCellRenderer]
author: aterai
pubdate: 2019-12-09T17:24:04+09:00
description: JComboBoxのアイテム文字列がJComboBox本体またはドロップダウンリストのセルから溢れる場合のみJToolTipを表示可能に設定します。
image: https://drive.google.com/uc?id=1Gm4SDovuAp3RO8gdLagvzxvj5wComdW3
---
* 概要 [#summary]
`JComboBox`のアイテム文字列が`JComboBox`本体またはドロップダウンリストのセルから溢れる場合のみ`JToolTip`を表示可能に設定します。

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

* サンプルコード [#sourcecode]
#code(link){{
private static <E> JComboBox<E> makeComboBox(ComboBoxModel<E> model) {
  return new JComboBox<E>(model) {
    @Override public void updateUI() {
      setRenderer(null);
      super.updateUI();
      ListCellRenderer<? super E> renderer = getRenderer();
      JComboBox<E> combo = this;
      JButton arrowButton = getArrowButton(this);
      setRenderer((list, value, index, isSelected, cellHasFocus) -> {
        Component r = renderer.getListCellRendererComponent(
            list, value, index, isSelected, cellHasFocus);
        JComponent c = (JComponent) r;
        // Insets i1 = combo.getInsets();
        Insets ins = c.getInsets();
        // int availableWidth = combo.getWidth() - i1.top - i1.bottom - ins.top - ins.bottom;
        Rectangle rect = SwingUtilities.calculateInnerArea(combo, null);
        // System.out.println(rect);
        int availableWidth = rect.width - ins.top - ins.bottom;

        String str = Objects.toString(value, "");
        FontMetrics fm = c.getFontMetrics(c.getFont());
        c.setToolTipText(fm.stringWidth(str) > availableWidth ? str : null);

        if (index < 0) {
          // @see BasicComboBoxUI#rectangleForCurrentValue
          // System.out.println(UIManager.getBoolean("ComboBox.squareButton"));
          // int buttonSize = combo.getHeight() - i1.top - i1.bottom; // - ins.top - ins.bottom;
          int buttonSize = Objects.nonNull(arrowButton) ? arrowButton.getWidth() : rect.height;
          availableWidth -= buttonSize;
          JTextField tf = (JTextField) combo.getEditor().getEditorComponent();
          availableWidth -= tf.getMargin().left + tf.getMargin().right;
          combo.setToolTipText(fm.stringWidth(str) > availableWidth ? str : null);
        }
        return c;
      });
    }

    private JButton getArrowButton(Container combo) {
      for (Component c: combo.getComponents()) {
        if (c instanceof JButton) {
          return (JButton) c;
        }
      }
      return null;
    }
  };
}
}}

* 解説 [#explanation]
上記のサンプルでは、`JComboBox`の本体、またはドロップダウンリストで文字列の溢れが発生する場合のみ`JToolTip`を表示するよう`ListCellRenderer`を設定しています。
上記のサンプルでは、`JComboBox`の本体またはドロップダウンリストで文字列の溢れが発生する場合のみ`JToolTip`を表示するよう`ListCellRenderer`を設定しています。

- `JComboBox`のドロップダウンリスト
-- `JComboBox`の内部ペイント領域の幅からセルレンダラーのインセットを引いた長さよりアイテム文字列の幅が短い場合に溢れが発生するので、レンダラーに`setToolTipText(...)`メソッドで省略前のアイテム文字列をツールチップ文字列として設定
- `JComboBox`の本体:
-- `JComboBox`の内部ペイント領域の幅からセルレンダラーのインセット、`ArrowButton`の幅、`EditorComponent`のインセットを引いた長さよりアイテム文字列の幅が短い場合に溢れが発生するので、`JComboBox`本体に`setToolTipText(...)`メソッドで省略前のアイテム文字列をツールチップ文字列として設定
-- `ArrowButton`の幅は、`UIManager.getBoolean("ComboBox.squareButton")`が`true`で正方形になる場合は`JComboBox`の高さから取得可能だが、このサンプルでは`JComboBox`の子`JButton`を検索して直接その幅を取得している
-- `ArrowButton`の幅は`UIManager.getBoolean("ComboBox.squareButton")`が`true`で正方形になる場合は`JComboBox`の高さから取得可能だが、このサンプルでは`JComboBox`の子`JButton`を検索して直接その幅を取得している
--- 参考: [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/plaf/basic/BasicComboBoxUI.html#squareButton BasicComboBoxUI#squareButton (Java Platform SE 8)]

* 参考リンク [#reference]
- [[JComboBoxの各アイテムやArrowButtonにそれぞれToolTipTextを設定する>Swing/ToolTipInComboBox]]
- [[JComboBoxのアイテム文字列を左側からクリップ>Swing/LeftClippedComboBox]]
- [https://stackoverflow.com/questions/59157543/jcombobox-with-tooltip-if-display-area-too-small-while-maintaining-look-and-fee java - JComboBox with tooltip if display area too small, while maintaining look and feel - Stack Overflow]

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