Многострочные всплывающие подсказки в Java?

105

Я пытаюсь отображать всплывающие подсказки на Java, которые могут иметь длину абзаца, а могут и нет. Как перенести длинные всплывающие подсказки по словам?

Аманда С
источник
Приведите пример кода.
Стефан Тиберг,
1
Разве подсказки не переносятся автоматически по словам, если они заключены в теги HTML? Я не уверен, поэтому я не использую это как ответ.
Пол Томблин,
Пол: Только если у вас есть явный перенос строки.
Amanda S,

Ответы:

146

Если вы заключаете всплывающую подсказку в <html>и </html>тегах, вы можете разбить строки с <br>тегами. См. Http://www.jguru.com/faq/view.jsp?EID=10653 для примеров и обсуждения.

Или вы можете использовать класс JMultiLineToolTip, который можно найти во многих местах в сети, включая https://github.com/ls-cwi/yoshiko-app/blob/master/src/main/java/com/yoshiko/internal/ просмотр / JMultiLineToolTip.java

Пол Томблин
источник
1
Я использовал предложенный вами класс JMultiLineToolTip. Когда я использовал setFixedWidth (), чтобы ограничить всплывающую подсказку разумным размером, она отлично сработала. Спасибо!
Amanda S
24

Текст всплывающей подсказки, начинающийся с " <html>", будет рассматриваться как HTML. Конечно, это может быть очень широкий HTML.

Вы можете переопределить JComponent.createTooltip, чтобы заменить всплывающую подсказку своим собственным компонентом, который может отображать все, что вам нравится.

Том Хотин - tackline
источник
20

Я знаю, что этот довольно старый, но я нашел довольно простое решение с использованием HTML-кода!

Просто используйте абзац HTML с фиксированной шириной:

setToolTipText("<html><p width=\"500\">" +value+"</p></html>");
Phwoelfel
источник
Что, если я хочу отобразить текст, который намного короче размера всплывающей подсказки? Тег "max-width" здесь не работает
nickolay.laptev
5

Используйте всплывающие подсказки HTML и вручную разбивайте строки (это должен сделать простой токенизатор слов с фиксированной длиной строки). Просто убедитесь, что текст вашей панели инструментов начинается с «<HTML>». Разрывайте строки с помощью «<BR/>» или «<P>». Я понимаю, что это не самое чистое решение, а поддержка HTML в Java ужасна, но с этим нужно работать.

басовый
источник
4

Пример:

jTextField1.setToolTipText("<html>"
                              + "Line One"
                              +"<br>"
                              + "Line 2"
                         + "</html>");
ja4
источник
Это не ответ на вопрос автора. Он спрашивал об упаковке, когда она отображается, а не в исходном коде.
Sled
2
@ArtB этот пример кода действительно дает всплывающую подсказку из двух строк, как и просили.
Thelema
4

Это можно было бы несколько улучшить, но мой подход был вспомогательной функцией, вызываемой перед установкой всплывающей подсказки, которая разделяла текст всплывающей подсказки на заданную длину, но настраивалась так, чтобы разбивать слова на пробел, где это возможно.

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();
    }
}

Использовать как

jComponent.setToolTipText(MultiLineTooltips.splitToolTip(TOOLTIP));
Пол Тейлор
источник
2

Вы можете создать подкласс JToolTip, который является компонентом, и переопределить createToolTip () в компоненте.

user101884
источник
1

Вот версия, которую я использовал раньше, она хорошо работает, если вы загружаете свои подсказки из 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);
    }

}

И вы могли бы использовать его, вызвав этот метод до создания вашего пользовательского интерфейса:

MultiLineToolTipUI.installUI();

Затем в файлах свойств просто вставьте новые строки, чтобы обернуть подсказки по своему усмотрению.

Ян Филлипс
источник
1

Я создал служебный класс, который автоматически форматирует строки до определенной длины с помощью <br>тегов. Он основан на классе MultiLineToolTips, опубликованном Полом Тейлором, но у него есть ошибка, которая пропускает части строки и фактически не ограничивает строку определенной длиной.

Чтобы использовать мой класс, просто вызовите метод splitToolTip, написав MultiLineToolTips.splitToolTip(yourString);или, MultiLineToolTips.splitToolTip(yourString, maxLength);если вы хотите разделить его до определенной максимальной длины. Это создаст красиво отформатированные строки подсказок.

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();
    }
}
Эндрю Лемэтр
источник
0

Если вы просто добавите <html>текст всплывающей подсказки, он будет работать до тех пор, пока в тексте не будет /*...*/HTML или HTML. Используйте <html><pre>или экранируйте свой текст. Мне также пришлось использовать, <font size=3>чтобы он выглядел несколько прилично.

NateS
источник