概要

JListのセル内に文字列が収まらない場合のみ、その上にToolTipを重ねて表示します。

サンプルコード

class TooltipList<E> extends JList<E> {
  public TooltipList(ListModel<E> m) {
    super(m);
  }

  @Override public Point getToolTipLocation(MouseEvent event) {
    Point pt = null;
    if (event != null) {
      Point p = event.getPoint();
      ListCellRenderer<? super E> r = getCellRenderer();
      int i = locationToIndex(p);
      Rectangle cb = getCellBounds(i, i);
      if (i != -1 && r != null && cb != null && cb.contains(p.x, p.y)) {
        ListSelectionModel lsm = getSelectionModel();
        Component rc = r.getListCellRendererComponent(
            this, getModel().getElementAt(i), i, lsm.isSelectedIndex(i),
            hasFocus() && lsm.getLeadSelectionIndex() == i);
        if (rc instanceof JComponent && ((JComponent) rc).getToolTipText() != null) {
          pt = cb.getLocation();
        }
      }
    }
    return pt;
  }
}
View in GitHub: Java, Kotlin

解説

  • 左: CellBounds
    • JList#getToolTipLocation()をオーバーライドして表示するJToolTipの原点をJList#getCellBounds(int, int)で取得したセル領域の左上に変更
  • 中: ListCellRenderer
    • JList#getToolTipLocation()をオーバーライドして表示するJToolTipの原点をJList#getCellBounds(int, int)で取得したセル領域の左上に変更
    • JList#createToolTip()をオーバーライドしてセルの描画に使用するセルレンダラー自体をJToolTipに追加
      • このため、対象セルが選択状態の場合JToolTipの背景色もそのセル選択色と同じになる
  • 右: Default
    • JToolTipの表示位置は、デフォルトのマウスカーソルの右下

  • セル内に文字列が収まっているかは以下のように調査している
    class TooltipListCellRenderer extends DefaultListCellRenderer {
      @Override public Component getListCellRendererComponent(
            JList list, Object value, int index, boolean isSelected, boolean hasFocus) {
        JLabel l = (JLabel) super.getListCellRendererComponent(
            list, value, index, isSelected, hasFocus);
        Insets i = l.getInsets();
        Container c = SwingUtilities.getAncestorOfClass(JViewport.class, list);
        Rectangle rect = c.getBounds();
        rect.width -= i.left + i.right;
        FontMetrics fm = l.getFontMetrics(l.getFont());
        String str = Objects.toString(value, "");
        l.setToolTipText(fm.stringWidth(str) > rect.width ? str : null);
        return l;
      }
    }
    

参考リンク

コメント