• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: ToolTipInComboBox
title: JComboBoxの各アイテムやArrowButtonにそれぞれToolTipTextを設定する
tags: [JComboBox, JToolTip, JLayer]
author: aterai
pubdate: 2017-04-24T14:34:47+09:00
description: JComboBoxの各リストアイテムやArrowButtonに、それぞれ異なるToolTipTextを設定します。
image: https://drive.google.com/uc?id=1-hvVHO5A6M8VTO8QPye3epe-ZazLLTzfDQ
---
* 概要 [#summary]
`JComboBox`の各リストアイテムや`ArrowButton`に、それぞれ異なる`ToolTipText`を設定します。

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

* サンプルコード [#sourcecode]
#code(link){{
private static JComponent makeComboBox() {
  JComboBox<String> combo = new JComboBox<>(new String[] {"aaa", "bbbbb", "c"});
  combo.setRenderer(new DefaultListCellRenderer() {
    @Override public Component getListCellRendererComponent(
        JList<?> list, Object value, int index,
        boolean isSelected, boolean cellHasFocus) {
      Component c = super.getListCellRendererComponent(
          list, value, index, isSelected, cellHasFocus);
      if (c instanceof JComponent) {
        ((JComponent) c).setToolTipText(String.format("Item%d: %s", index, value));
      }
      return c;
    }
  });
  return new JLayer<>(combo, new ToolTipLayerUI<>());
}

class ToolTipLayerUI<V extends JComboBox> extends LayerUI<V> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }
  }

  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }

  @Override protected void processMouseMotionEvent(
        MouseEvent e, JLayer<? extends V> l) {
    JComboBox<?> c = l.getView();
    if (e.getComponent() instanceof JButton) {
      c.setToolTipText("JButton");
    } else {
      c.setToolTipText("JComboBox: " + c.getSelectedItem());
    }
    super.processMouseMotionEvent(e, l);
  }
}
}}

* 解説 [#explanation]
- `JComboBox`本体
-- `JComboBox#setToolTipText(...)`メソッドで`ToolTipText`を設定した場合、`ArrowButton`や編集可の場合の`JTextField`などのすべての子コンポーネントに同じテキストが設定される
--- 参考: `BasicComboBoxUI#updateToolTipTextForChildren()`
-- ドロップダウンリスト内のリストアイテムに`ToolTipText`は設定されない
- リストアイテム
-- セルレンダラーに`DefaultListCellRenderer#setToolTipText(...)`メソッドで`ToolTipText`を設定
- `ArrowButton`
-- `JComboBox`本体とは別の`ToolTipText`を設定するため、`JLayer`を使用
--- `LayerUI#processMouseMotionEvent(...)`をオーバーライドして、`JButton`上にマウスカーソルが入ったら`JButton#setToolTipText(...)`で`ToolTipText`を変更

----
- `JComboBox`のドロップダウンリストを開いた状態でツールチップを表示すると描画が乱れる場合がある
- `JComboBox`にフォーカスが存在する状態でドロップダウンリストを開き(`ArrowButton`をマウスクリックではなく、`JComboBox`本体をマウスクリック、またはKBD{Space}キーを使用)ツールチップを表示すると描画が乱れる場合がある
-- `MetalLookAndFeel`のみ
-- ドロップダウンリストが`HeavyWeightWindow`か`LightWeightWindow`かは無関係

#img2(https://drive.google.com/uc?id=1l662LOjb0AFVh6F9lOSm78ZsXzJfuG0GDQ)

#code{{
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CustomJComboBoxTest2 {
  public JComponent makeUI() {
    JComboBox<String> box = new JComboBox<>();
    box.addItem("Item 1");
    box.addItem("Item 2");
    box.setToolTipText("TooTip");

    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createEmptyBorder(60, 20, 60, 20));
    p.add(box);
    return p;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new CustomJComboBoxTest2().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
}}

* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/plaf/LayerUI.html#processMouseMotionEvent-java.awt.event.MouseEvent-javax.swing.JLayer- LayerUI#processMouseMotionEvent(MouseEvent, JLayer) (Java Platform SE 8)]

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