Swing HTML drawString

13

我正在尝试为特定目的创建一些特殊组件,在该组件上我需要绘制HTML字符串,以下是示例代码:

 public class MyComponent extends JComponent{
     public MyComponent(){
        super();
     }

     protected void paintComponent(Graphics g){
        //some drawing operations...
        g.drawString("<html><u>text to render</u></html>",10,10);
     }
 }

很遗憾,drawString方法似乎无法识别HTML格式,它会愚蠢地按原样绘制字符串。

有没有办法让它正常工作?


3
为什么不使用JLabel?它支持HTML标签。 - Eng.Fouad
我的组件不仅仅绘制一个HTML字符串,还有很多其他的绘图操作,但我并不想在示例代码中展示它们,只想集中解决实际问题。 - George Casttrey
“特别”是指什么?“具体”又是什么?回答这个问题会建议添加更多的细节,而不是减少。 - Andrew Thompson
7个回答

12
如果您是Java2D的粉丝,并且想要在Swing组件和布局中充分利用HTML,我建议您使用@camickr建议的组件方法。如果需要,您可以使用JTable等中看到的轻量级渲染器方法,其中一个组件被重复使用进行绘图。下面的示例是该技术的一个非常简化的概述,仅更改颜色和位置。
附加说明: 更新示例;还请参见CellRendererPane让您的应用飞起来:实现Flyweight以提高性能

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.CellRendererPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/** @see https://dev59.com/a2sz5IYBdhLWcg3wmpP0 */
public class PaintComponentTest extends JPanel {

    private static final int N = 8;
    private static final String s = "<html><big><u>Hello</u></html>";
    private JLabel renderer = new JLabel(s);
    private CellRendererPane crp = new CellRendererPane();
    private Dimension dim;

    public PaintComponentTest() {
        this.setBackground(Color.black);
        dim = renderer.getPreferredSize();
        this.add(crp);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < N; i++) {
            renderer.setForeground(Color.getHSBColor((float) i / N, 1, 1));
            crp.paintComponent(g, renderer, this,
                i * dim.width, i * dim.height, dim.width, dim.height);
        }
    }

    private void display() {
        JFrame f = new JFrame("PaintComponentTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setSize(dim.width * N, dim.height * (N + 1));
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new PaintComponentTest().display();
            }
        });
    }
}

非常感谢您的帮助。我已经找到另一种方法来完成这个,而不需要使用CellRendererPane。(请看我的回答帖子)。 - George Casttrey
1
不用谢。CellRendererPane 提供了一些方便的缓存和验证优化,这可能在未来证明有用。 - trashgod

10

正如其他人所评论的那样,Swing组件支持HTML 3.2和基本样式。

有关如何在paintComponent(Graphics)方法中利用该功能的详细信息,请参见此线程上的LabelRenderTest.java源代码。

方法是将标签渲染为图像,然后将该图像渲染到Graphics对象中。


我已经找到了一种使用JLabel绘制htmlString的方法,但不需要渲染图像(请查看我的帖子)。非常感谢您的帮助。 - George Casttrey

7
您的问题的答案是HTML不被支持。
简单的解决方案是使用Swing组件并正确布局。
如果您想自己操作,那么您需要操纵用于drawString()方法的字体。您可以使用斜体、粗体等字体。

非常感谢您的答复,它帮助我正确思考了。 - George Casttrey

6

我找到了一种简洁的方法来模拟paintHtmlString;以下是代码:

public class MyComponent extends JComponent {

    private JLabel label = null;

    public MyComponent() {
        super();
    }

    private JLabel getLabel() {
        if (label == null) {
            label = new JLabel();
        }
        return label;
    }

    /**
     * x and y stand for the upper left corner of the label
     * and not for the baseline coordinates ...
     */
    private void paintHtmlString(Graphics g, String html, int x, int y) {
        g.translate(x, y);
        getLabel().setText(html);
        //the fontMetrics stringWidth and height can be replaced by
        //getLabel().getPreferredSize() if needed
        getLabel().paint(g);
        g.translate(-x, -y);
    }

    protected void paintComponent(Graphics g) {
        //some drawing operations...
        paintHtmlString(g, "<html><u>some text</u></html>", 10, 10);
    }
}

非常感谢大家的帮助,我非常感激。


正如这里所提到的,如果JLabel从未被添加到过已经pack()过(或等效的)Frame下,则可能需要执行getLabel().setSize(getLabel().getPreferredSize()) - Evgeni Sergeev

5
使用JLabel作为基类。Graphics.drawString()只能绘制字符串内容。

我的组件不仅仅绘制HTML字符串,还有很多其他的绘图操作,我不想在示例代码中展示它们,只是为了专注于真正的问题。我知道JLabel和所有其他包含文本的Swing组件都支持HTML格式。<br/> 我只是想知道是否有任何方法可以通过Graphics实例呈现HTML文本。 - George Casttrey

5

这种实现方式是不正确的。

drawString(String str, int x, int y)方法仅使用当前图形上下文的字体和颜色绘制指定字符串的文本。

您可以从这里获取更多有关问题的信息:如何在Swing组件中使用HTML


谢谢你的回答,它帮助我朝着正确的方向前进。 - George Casttrey

2

在使用Graphics绘制HTML时并没有简单的方法,建议使用JLabel。

然而,有一种有趣的方法可以通过创建一个带有HTML的JLabel并将其绘制到组件上来实现:

private JLabel label;

public MyComponent() {
    label = new JLabel("Before Red");
    label.setText("<html><u>test</u></html>");
    this.add(label);
}

public void repaint(Graphics g){
    g = label.getGraphics();
}

最简单的方法是为您的图形设置字体,例如:

public void repaint(Graphics g){    
    Font f = new Font("Courier", Font.BOLD, 12);
    g.setFont(f);
    g.drawString("Bolded Courier", 5, 15);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接