• 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

概要

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

サンプルコード

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 in GitHub: Java, Kotlin

解説

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

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

参考リンク

コメント