Zielony Smok - logo witryny

Ten wpis napisałem korzystając z materiałów udostępnionych przez córkę.

Jak wiemy – w języku Java podpowiedzi można formatować przy użyciu HTML.

Podpowiedzi można też formatować bez użycia HTML. W tym wpisie właśnie to pokazuję.

Klasy

Aby móc formatować podpowiedzi należy przede wszystkim przygotować 2 klasy:

  • RectToolTip
  • RectToolTipUI

Potem tworzymy klasę przycisku MyButton, w którym nadpisujemy metodę createToolTip().

W klasach:

  • Main1 – pokazuje niesformatowaną podpowiedź w normalnym przycisku JButton
  • Main2 do przycisku MyButton dodajemy podpowiedź przy użyciu metody setTooltip(Tooltip)
  • Main3 – przy tworzeniu normalnego JButton nadpisujemy metodę createToolTip()
RectToolTip.java
package tooltip1;

import javax.swing.*;

public class RectToolTip extends JToolTip {
    private static final long serialVersionUID = 2381804711089908434L;

    public RectToolTip() {
        setUI(new RectToolTipUI());
    }
}
RectToolTipUI
package tooltip1;

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

public class RectToolTipUI extends MetalToolTipUI {
    private String[] tokeny;
    @SuppressWarnings("unused")
    private int maxWidth = 0;
    private int rectW = 0;

    @Override
    public void paint(Graphics g, JComponent c) {
        FontMetrics fm = g.getFontMetrics(g.getFont());
        Dimension size = c.getSize();
        g.setColor(c.getBackground());
        g.fillRect(0, 0, size.width, size.height);
        g.setFont(c.getFont());
        g.setColor(c.getForeground());
        int curX = 5;//polozenie tekstu na scenie
        int curY = 15;//polozenie tekstu na scenie
        int akt;//szerokosc aktualnie wypisywanego slowa
        @SuppressWarnings("unused")
        int rows = 1;//liczba linii tekstu
        for (String s : tokeny) {
            akt = fm.stringWidth(s);//sprawdza szerokosc stringu
            //w pikselach
            if ((curX + akt) < rectW + 5) {//jesli sie miesci w ramce
                g.drawString(s, curX, curY);//to wypisuje
                curX += akt;//zmienia pozycje "glowicy"
            } else {//jesli sie nie miesci
                curX = 5;//to przenosi "glowice" na poczatk
                curY += fm.getHeight();//i do nowego wiersza
                rows++;//dodaje nowy rzad
                g.drawString(s, curX, curY);//wypisuje string
                curX += akt;//zmienia pozycje "glowicy"
            }
        }
    }

    @Override
    public Dimension getPreferredSize(JComponent c) {
        FontMetrics fm = c.getFontMetrics(c.getFont());
        String tipText = ((JToolTip) c).getTipText();
        if (tipText == null) {
            tipText = "";
        }
        StringTokenizer st = new StringTokenizer(tipText, " ", true);
        int tokNum = st.countTokens();
        tokeny = new String[tokNum];
        int i = -1;
        int maxStrLen = 0;
        String maxString = null;
        while (st.hasMoreTokens()) {
            i++;
            String val = st.nextToken();//pobiera token
            tokeny[i] = val;//przypisuje token do tablicy
            int valLen = val.length();//sprawdza ilosc znakow w tokenie
            if (valLen > maxStrLen) {//sprawdza czy token jest najdluzszy
                maxStrLen = valLen;//jesli tak to ustawia dlugosc
                maxString = tokeny[i];//i pobiera ten string
            }
        }
        int textH = fm.getHeight();
        int textW = fm.stringWidth(tipText);
        int textArea = textH * textW;
        rectW = (int) Math.round(Math.sqrt(textArea / 0.62));
        int len1 = fm.stringWidth(maxString);
        if (rectW < len1 + 5) {
            rectW = len1 + 10;
        }
        int curX = 5;//polozenie tekstu na scenie
        @SuppressWarnings("unused")
        int curY = 15;//polozenie tekstu na scenie
        int akt;//szerokosc aktualnie wypisywanego slowa
        int rows = 1;//liczba linii tekstu
        for (i = 0; i < tokeny.length; i++) {
            akt = fm.stringWidth(tokeny[i]);//sprawdza szerokosc stringu
            //w pikselach
            if ((curX + akt) < rectW + 5) {//jesli sie miesci w ramce
                curX += akt;//zmienia pozycje "glowicy"
            } else {//jesli sie nie miesci
                curX = 5;//to przenosi "glowice" na poczatk
                curY += fm.getHeight();//i do nowego wiersza
                rows++;//dodaje nowy rzad
                curX += akt;//zmienia pozycje "glowicy"
            }
        }
        int dismissDelay = 4000;
        if (rows > 4) {
            dismissDelay = rows * 1300;
        }
        ToolTipManager.sharedInstance().setDismissDelay(dismissDelay);
        return new Dimension(rectW + 8, rows * fm.getHeight() + 5);
    }
}
MyButton.java
package tooltip1;

import java.awt.*;
import javax.swing.*;

public class /**/MyButton extends JButton {
    private static final long serialVersionUID = 3602182470147405262L;

    MyButton() {
        super();
    }

    MyButton(Action a) {
        super(a);
    }

    MyButton(Icon icon) {
        super(icon);
    }

    MyButton(String text) {
        super(text);
    }

    MyButton(String text, Icon icon) {
        super(text, icon);
    }

    @Override
    public JToolTip createToolTip() {
        RectToolTip tip = new RectToolTip();
        tip.setComponent(this);
        tip.setBackground(Color.GREEN);
        tip.setForeground(Color.BLUE);
        tip.setFont(new Font("Dialog", Font.ITALIC, 14));
        return tip;
    }
}
Main1.java
package tooltip1;

import javax.swing.*;
import java.awt.*;

/**
 * ramka + panel
 */
public class Main1 extends JFrame {
    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Main1());
    }

    public Main1() {
        setLayout(null);
        setPreferredSize(new Dimension(800, 800));
        int frameHeight = 800;
        int frameWidth = 800;
        setBounds((Toolkit.getDefaultToolkit().getScreenSize().width / 2)
                        - (frameWidth / 2), (Toolkit.getDefaultToolkit()
                        .getScreenSize().height / 2) - (frameHeight / 2), frameWidth,
                frameHeight);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Ramka Graficzna");
        //  setResizable(false);
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setBounds(0, 0, frameWidth, frameHeight);
        JButton but = new JButton("Button");
        String str = "Jest to moment konkretyzowania planów. Wskazuje na początek dziaia albo nowy fakt w życiu pytającego. Należy uważnie rozważyć karty sąsiednie. Karta ta oznacza przede wszystkim pracę, plany i dzieci. Może wskazywać na początek nowego, ważnego etapu w życiu pytającego. Spotkanie z drugim człowiekiem (w towarzystwie karty Diabeł - akt seksualny). Niezależność jest korzystna dla pytającego. Pytający może narzucić swoją wolę, kontynuować wysiłek i zrealizować plany. Karta ta często reprezentuje młodą osobę (o ile nie występuje w towarzystwie karty Pustelnik), albo pytającego, o ile nie przekroczył czterdziestki. Mag w sąsiedztwie karty Słoñce reprezentuje miłość męską.";
        but.setToolTipText(str);
        but.setBounds(100, 100, 100, 40);
        panel.add(but);
        add(panel);
        setVisible(true);
    }
}

Efektem najechania kurorem myszy na przycisk jest:

Formatowanie tekstu podpowiedzi (bez użycia HTML)
Rys. 159. Klasyczna podpowiedź (wychodzi poza ekran)
Main2.java
package tooltip1;

import java.awt.*;
import javax.swing.*;

/**
 * ramka + panel
 */
public class Main2 extends JFrame{
	private static final long serialVersionUID = 1L;

	public static void main(String[] args) {
		SwingUtilities.invokeLater(() -> new Main2());
	}

	public Main2(){
		setLayout(null);
		setPreferredSize(new Dimension(800, 800));
		int frameHeight = 800;
		int frameWidth = 800;
		setBounds((Toolkit.getDefaultToolkit().getScreenSize().width / 2)
				- (frameWidth / 2), (Toolkit.getDefaultToolkit()
				.getScreenSize().height / 2) - (frameHeight / 2), frameWidth,
				frameHeight);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("Ramka Graficzna");
		//  setResizable(false);
		JPanel panel = new JPanel();
		panel.setLayout(null);
		panel.setBounds(0, 0, frameWidth, frameHeight);
		MyButton but = new MyButton("Button");
		String str = "Jest to moment konkretyzowania planów. Wskazuje na początek dziaia albo nowy fakt w życiu pytającego. Należy uważnie rozważyć karty sąsiednie. Karta ta oznacza przede wszystkim pracę, plany i dzieci. Może wskazywać na początek nowego, ważnego etapu w życiu pytającego. Spotkanie z drugim człowiekiem (w towarzystwie karty Diabeł - akt seksualny). Niezależność jest korzystna dla pytającego. Pytający może narzucić swoją wolę, kontynuować wysiłek i zrealizować plany. Karta ta często reprezentuje młodą osobę (o ile nie występuje w towarzystwie karty Pustelnik), albo pytającego, o ile nie przekroczył czterdziestki. Mag w sąsiedztwie karty Słoñce reprezentuje miłość męską.";
		but.setToolTipText(str);
		but.setBounds(100, 100, 100, 40);
		panel.add(but);
		add(panel);
		setVisible(true);
	}
}

Efektem uruchomienia i najechania kursorem myszy na przycisk jest:

Formatowanie tekstu podpowiedzi (bez użycia HTML)
Rys. 160. Sformatowana podpowiedź – sposób 1
Main3.java
package tooltip1;

import java.awt.*;
import javax.swing.*;

/**
 * ramka + panel
 */
public class Main3 extends JFrame {
    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Main3());
    }

    public Main3() {
        setLayout(null);
        setPreferredSize(new Dimension(800, 800));
        int frameHeight = 800;
        int frameWidth = 800;
        setBounds((Toolkit.getDefaultToolkit().getScreenSize().width / 2)
                        - (frameWidth / 2), (Toolkit.getDefaultToolkit()
                        .getScreenSize().height / 2) - (frameHeight / 2), frameWidth,
                frameHeight);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Ramka Graficzna");
        //  setResizable(false);
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setBounds(0, 0, frameWidth, frameHeight);
        JButton but = new JButton("Button") {
            private static final long serialVersionUID = -50399866112532871L;

            @Override
            public JToolTip createToolTip() {
                RectToolTip tip = new RectToolTip();
                tip.setComponent(this);
                tip.setBackground(Color.YELLOW);
                tip.setForeground(Color.RED);
                tip.setFont(new Font("Dialog", Font.ITALIC, 12));
                return tip;
            }
        };
        String str = "Jest to moment konkretyzowania planów. Wskazuje na początek działania albo nowy fakt w życiu pytającego. Należy uważnie rozważyć karty sąsiednie. Karta ta oznacza przede wszystkim pracę, plany i dzieci. Może wskazywać na początek nowego, ważnego etapu w życiu pytającego. Spotkanie z drugim człowiekiem (w towarzystwie karty Diabeł - akt seksualny). Niezależność jest korzystna dla pytającego. Pytający może narzucić swoją wolę, kontynuować wysiłek i zrealizować plany. Karta ta często reprezentuje młodą osobę (o ile nie występuje w towarzystwie karty Pustelnik), albo pytającego, o ile nie przekroczył czterdziestki. Mag w sąsiedztwie karty Słońce reprezentuje miłość męską.";
        but.setToolTipText(str);
        but.setBounds(100, 100, 100, 40);
        panel.add(but);
        add(panel);
        setVisible(true);
    }
}

Efektem najechania kursorem myszy na przycisk jest:

Formatowanie tekstu podpowiedzi (bez użycia HTML)
Rys. 161. Sformatowana podpowiedź – sposób 2