112

I'm trying to display tooltips in Java which may or may not be paragraph-length. How can I word-wrap long tooltips?

Amanda S
  • 3,266
  • 4
  • 33
  • 45

10 Answers10

157

If you wrap the tooltip in <html> and </html> tags, you can break lines with <br> tags. See https://web.archive.org/web/20060625031340/http://www.jguru.com/faq/view.jsp?EID=10653 for examples and discussion. Main take-awy from that discussion: fButton.setToolTipText("<html><font face=\"sansserif\" color=\"green\">first line<br>second line</font></html>");

Or you can use the JMultiLineToolTip class that can be found many places on the net, including https://github.com/ls-cwi/yoshiko-app/blob/master/src/main/java/com/yoshiko/internal/view/JMultiLineToolTip.java

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
24

I know this one is quite old but i found a quite simple solution using HTML code!

Just use a HTML Paragraph with a fixed width:

setToolTipText("<html><p width=\"500\">" +value+"</p></html>");
phwoelfel
  • 358
  • 2
  • 5
24

Tooltip text which starts with "<html>" will be treated as HTML. Of course that might be very wide HTML.

You can override JComponent.createTooltip to replace the tooltip with your own component which can display whatevee you like.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
6

Example:

jTextField1.setToolTipText("<html>"
                              + "Line One"
                              +"<br>"
                              + "Line 2"
                         + "</html>");
ja4
  • 416
  • 5
  • 11
  • This does not answer the asker's question. He was asking about wrapping when it is displayed, not in source code. – Sled Nov 20 '12 at 14:38
  • 3
    @ArtB this example code does give a two-line tooltip as asked. – Thelema May 07 '13 at 18:15
  • @ja4 This example code help me to make multi-line tooltips, very easy way – Chauncey Lee Apr 29 '21 at 07:37
  • @Sled Actually, it does answer the question, whether unintentionally or not. All tooltip texts in Java which are wrapped in the tag are line broken automatically. So if "Line 1" would be really long for example, it would multi-line itself, making "Line 2" the third or fourth line. – Nico Wawrzyniak Jul 12 '21 at 19:18
5

Use HTML tooltips and manually break your lines (a simple word tokenizer with a fixed line length should do it). Just make sure your tooltip text starts with "<HTML>". Break lines with "<BR/>" or "<P>". I realize it's not the most clean solution and Java's HTML support is horrible, but it should get things done.

gouessej
  • 3,640
  • 3
  • 33
  • 67
basszero
  • 29,624
  • 9
  • 57
  • 79
4

This could be improved somewhat, but my approach was a helper function called before setting tooltip that split the tooltip text at provided length, but adjusted to break words on space where possible.

import java.util.ArrayList;
import java.util.List;

/**
 *
 */
public class MultiLineTooltips
{
    private static int DIALOG_TOOLTIP_MAX_SIZE = 75;
    private static final int SPACE_BUFFER = 10;

    public static String splitToolTip(String tip)
    {
        return splitToolTip(tip,DIALOG_TOOLTIP_MAX_SIZE);
    }
    public static String splitToolTip(String tip,int length)
    {
        if(tip.length()<=length + SPACE_BUFFER )
        {
            return tip;
        }

        List<String>  parts = new ArrayList<>();

        int maxLength = 0;
        String overLong = tip.substring(0, length + SPACE_BUFFER);
        int lastSpace = overLong.lastIndexOf(' ');
        if(lastSpace >= length)
        {
            parts.add(tip.substring(0,lastSpace));
            maxLength = lastSpace;
        }
        else
        {
            parts.add(tip.substring(0,length));
            maxLength = length;
        }

        while(maxLength < tip.length())
        {
            if(maxLength + length < tip.length())
            {
                parts.add(tip.substring(maxLength, maxLength + length));
                maxLength+=maxLength+length;
            }
            else
            {
                parts.add(tip.substring(maxLength));
                break;
            }
        }

        StringBuilder  sb = new StringBuilder("<html>");
        for(int i=0;i<parts.size() - 1;i++)
        {
            sb.append(parts.get(i)+"<br>");
        }
        sb.append(parts.get(parts.size() - 1));
        sb.append(("</html>"));
        return sb.toString();
    }
}

Use like

jComponent.setToolTipText(MultiLineTooltips.splitToolTip(TOOLTIP));
Paul Taylor
  • 13,411
  • 42
  • 184
  • 351
2

You can subclass JToolTip, which is a Component, and override createToolTip() on the component.

user101884
  • 717
  • 3
  • 7
1

Here is a version which I have used before, it works well if you are loading your tool tips from ResourceBundles:

import javax.swing.JComponent;
import javax.swing.JToolTip;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolTipUI;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.util.regex.Pattern;

/**
 * A tooltip that wraps multi-line text.
 */
public final class MultiLineToolTipUI extends ToolTipUI {

    private static final int INSET = 2;

    private static final Pattern LINE_SPLITTER = Pattern.compile("$", Pattern.MULTILINE);

    private static final MultiLineToolTipUI SHARED_INSTANCE = new MultiLineToolTipUI();

    /**
     * Install the multi-line tooltip into the UI manager.
     */
    public static void installUI() {
        String toolTipUI = MultiLineToolTipUI.class.getName();
        UIManager.put("ToolTipUI", toolTipUI);
        UIManager.put(toolTipUI, MultiLineToolTipUI.class);
    }

    @SuppressWarnings("UnusedDeclaration")
    public static ComponentUI createUI(JComponent c) {
        return SHARED_INSTANCE;
    }

    private MultiLineToolTipUI() {}

    @Override
    public Dimension getMaximumSize(JComponent c) {
        return getPreferredSize(c);
    }

    @Override
    public Dimension getMinimumSize(JComponent c) {
        return getPreferredSize(c);
    }

    @Override
    public Dimension getPreferredSize(JComponent c) {
        String[] lines = LINE_SPLITTER.split(((JToolTip) c).getTipText());
        if (lines.length == 0) {
            return new Dimension(2 * INSET, 2 * INSET);
        }
        FontMetrics metrics = c.getFontMetrics(c.getFont());
        Graphics g = c.getGraphics();
        int w = 0;
        for (String line : lines) {
            w = Math.max(w, (int) metrics.getStringBounds(line, g).getWidth());
        }
        int h = lines.length * metrics.getHeight();
        return new Dimension(w + 2 * INSET, h + 2 * INSET);
    }

    @Override
    public void installUI(JComponent c) {
        LookAndFeel.installColorsAndFont(c, "ToolTip.background", "ToolTip.foreground", "ToolTip.font");
        LookAndFeel.installBorder(c, "ToolTip.border");
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        int w = c.getWidth(), h = c.getHeight();
        g.setColor(c.getBackground());
        g.fillRect(0, 0, w, h);
        g.setColor(c.getForeground());
        g.drawRect(0, 0, w, h);
        String[] lines = LINE_SPLITTER.split(((JToolTip) c).getTipText());
        if (lines.length != 0) {
            FontMetrics metrics = c.getFontMetrics(c.getFont());
            int height = metrics.getHeight();
            int y = INSET + metrics.getAscent();
            for (String line : lines) {
                g.drawString(line, INSET, y);
                y += height;
            }
        }
    }

    @Override
    public void uninstallUI(JComponent c) {
        LookAndFeel.uninstallBorder(c);
    }

}

And you would use it by calling this method, before your UI is created:

MultiLineToolTipUI.installUI();

Then in your properties files just insert newlines to wrap your tool tips as desired.

Ian Phillips
  • 163
  • 1
  • 6
1

If you just add <html> to your tooltip text, it will appear to work until you have /*...*/ or HTML in your text. Use <html><pre> or escape your text. I also had to use <font size=3> to get it looking somewhat decent.

NateS
  • 5,751
  • 4
  • 49
  • 59
1

I created a utility class that automatically formats strings to a specific length with <br> tags. It is based on the MultiLineToolTips class posted by Paul Taylor, but his has a bug in it that skips portions of the string and does not actually limit the string to a specific length.

To use my class, simply invoke the splitToolTip method by writing MultiLineToolTips.splitToolTip(yourString); or MultiLineToolTips.splitToolTip(yourString, maxLength); if you want to split it to a specific maximum length. This will create nicely formatted tool tip strings.

import java.util.ArrayList;
import java.util.List;

/** A helper class to split strings into a certain length,
 * formatted with html {@literal<br>} tags for multi-line tool tips.
 * Based on the MultiLineToolTips class posted by
 * <a href="https://stackoverflow.com/users/1480018/paul-taylor">Paul Taylor</a>
 * on <a href="https://stackoverflow.com/a/13503677/9567822">Stack Overflow</a>
 * @author <a href="https://stackoverflow.com/users/9567822/andrew-lemaitre?tab=profile">Andrew LeMaitre</a>
 */
public final class MultiLineToolTips {

    /** Private constructor for utility class. */
    private MultiLineToolTips() {
    }

    /** Default max length of the tool tip when split with {@link #splitToolTip(String)}. */
    private static final int DIALOG_TOOLTIP_MAX_SIZE = 75;

    /** A function that splits a string into sections of {@value #DIALOG_TOOLTIP_MAX_SIZE} characters or less.
     * If you want the lines to be shorter or longer call {@link #splitToolTip(String, int)}.
     * @param toolTip The tool tip string to be split
     * @return the tool tip string with HTML formatting to break it into sections of the correct length
     */
    public static String splitToolTip(final String toolTip) {
        return splitToolTip(toolTip, DIALOG_TOOLTIP_MAX_SIZE);
    }

    /**  An overloaded function that splits a tool tip string into sections of a specified length.
     * @param toolTip The tool tip string to be split
     * @param desiredLength The maximum length of the tool tip per line
     * @return The tool tip string with HTML formatting to break it into sections of the correct length
     */
    public static String splitToolTip(final String toolTip, final int desiredLength) {
        if (toolTip.length() <= desiredLength) {
            return toolTip;
        }

        List<String>  parts = new ArrayList<>();
        int stringPosition = 0;

        while (stringPosition < toolTip.length()) {
            if (stringPosition + desiredLength < toolTip.length()) {
                String tipSubstring = toolTip.substring(stringPosition, stringPosition + desiredLength);
                int lastSpace = tipSubstring.lastIndexOf(' ');
                if (lastSpace == -1 || lastSpace == 0) {
                    parts.add(toolTip.substring(stringPosition, stringPosition + desiredLength));
                    stringPosition += desiredLength;
                } else {
                    parts.add(toolTip.substring(stringPosition, stringPosition + lastSpace));
                    stringPosition += lastSpace;
                }
            } else {
                parts.add(toolTip.substring(stringPosition));
                break;
            }
        }

        StringBuilder  sb = new StringBuilder("<html>");
        for (int i = 0; i < parts.size() - 1; i++) {
            sb.append(parts.get(i) + "<br>");
        }
        sb.append(parts.get(parts.size() - 1));
        sb.append(("</html>"));
        return sb.toString();
    }
}