概要

JComboBoxのアイテム文字列がJComboBox本体またはドロップダウンリストのセルから溢れる場合のみJToolTipを表示可能に設定します。

スクリーンショット

Swing/ComboBoxOverflowToolTips.png

サンプルコード

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;
    }
  };
}
view all

解説

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

  • JComboBoxのドロップダウンリスト
    • JComboBoxの内部ペイント領域の幅からセルレンダラーのインセットを引いた長さよりアイテム文字列の幅が短い場合に溢れが発生するので、レンダラーにsetToolTipText(...)メソッドで省略前のアイテム文字列をツールチップ文字列として設定
  • JComboBoxの本体:
    • JComboBoxの内部ペイント領域の幅からセルレンダラーのインセット、ArrowButtonの幅、EditorComponentのインセットを引いた長さよりアイテム文字列の幅が短い場合に溢れが発生するので、JComboBox本体にsetToolTipText(...)メソッドで省略前のアイテム文字列をツールチップ文字列として設定
    • ArrowButtonの幅は、UIManager.getBoolean("ComboBox.squareButton")trueで正方形になる場合はJComboBoxの高さから取得可能だが、このサンプルではJComboBoxの子JButtonを検索して直接その幅を取得している

参考リンク

コメント