如何禁用JLabel的自动HTML支持?

2022-09-03 05:50:36

Swing JLabel 会自动将任何文本解释为 HTML 内容,如果它以 <html> 开头。如果此HTML的内容是具有无效URL的图像,这将导致整个GUI挂起,因为应该加载此图像的ImageFetche将被NPE退出。

要重现此问题,只需创建一个 JLabel,如下所示

new JLabel("<html><img src='http:\\\\invalid\\url'>")

我知道有一个客户端属性可以防止JLabel解释HTML。但是JLabel是许多Swing组件(如JTree,JTable等)的默认渲染器实现,这使得这对于几乎任何允许用户输入的Swing应用程序来说都是一个问题。因此,我不是在实现大量的自定义渲染器,而是在寻找一个全局解决方案来禁用HTML解释。


答案 1

有一种方法可以创建自己的外观和感觉。
我不确定这有多好,但它有效。假设您将扩展“Classic Windows”L&F.您需要在leas 2类一个是Look&Feel本身,让我们称之为WindowsClassicLookAndFeelExt。您只需要重写方法 initClassDefaults。

package testSwing;

import javax.swing.UIDefaults;
import com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel;

public class WindowsClassicLookAndFeelExt extends WindowsClassicLookAndFeel    {
    @Override protected void initClassDefaults(UIDefaults table){
        super.initClassDefaults(table);
        Object[] uiDefaults = { "LabelUI", WindowsLabelExtUI.class.getCanonicalName()};
        table.putDefaults(uiDefaults);
    }
}

您还需要一个 WindowsLabelExtUI 类来管理所有 JLabels 并设置属性:

package testSwing;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import com.sun.java.swing.plaf.windows.WindowsLabelUI;

public class WindowsLabelExtUI extends WindowsLabelUI{
    static WindowsLabelExtUI singleton = new WindowsLabelExtUI();

    public static ComponentUI createUI(JComponent c){
        c.putClientProperty("html.disable", Boolean.TRUE);    
        return singleton;
    }
}

最后,当您将主题设置为WindowsClassicLookAndFeelExt时,这是一个测试类

package testSwing;

import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.UIManager;


public class Main{
    public static void main(String[] args){
        try{                UIManager.setLookAndFeel(WindowsClassicLookAndFeelExt.class.getCanonicalName());
        }catch (Exception e){
            e.printStackTrace();
        }

        JFrame frame = new JFrame("JList Test");
        frame.setLayout(new FlowLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String[] selections = {"<html><img src='http:\\\\invalid\\url'>", "<html><H1>Hello</h1></html>", "orange", "dark blue"};

        JList list = new JList(selections);

        list.setSelectedIndex(1);
        System.out.println(list.getSelectedValue());

        JLabel jLabel = new JLabel("<html><h2>standard Label</h2></html>");
        frame.add(new JScrollPane(list));
        frame.add(jLabel);
        frame.pack();

        frame.setVisible(true);
    }
}

你会看到类似的东西

alt text


答案 2

对于一个简单的 JLabel,你可以调用 JComponent 方法

myLabel.putClientProperty("html.disable", Boolean.TRUE);

在要禁用 HTML 呈现的标签上。

参考:不可能在 JLabel 中禁用 HTML 呈现


对于 JTable、JTree 或 JList 之类的东西,您需要创建一个设置此属性的自定义单元格呈现器。下面是一个示例(从此示例修改而来),它为 JList 创建自定义单元格呈现器。

import java.awt.Component;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;

public class JListTest {
    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("JList Test");
        frame.setLayout(new FlowLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        String[] selections = { "<html><img src='http:\\\\invalid\\url'>",
                "red", "orange", "dark blue" };
        JList list = new JList(selections);

        // set the list cell renderer to the custom class defined below
        list.setCellRenderer(new MyCellRenderer());

        list.setSelectedIndex(1);
        System.out.println(list.getSelectedValue());
        frame.add(new JScrollPane(list));
        frame.pack();

        frame.setVisible(true);
    }
}


class MyCellRenderer extends JLabel implements ListCellRenderer {
    public MyCellRenderer() {
        setOpaque(true);
        putClientProperty("html.disable", Boolean.TRUE);
    }

    public Component getListCellRendererComponent(
        JList list,
        Object value,
        int index,
        boolean isSelected,
        boolean cellHasFocus)
    {
        setText(value.toString());
        return this;
    }
}

我使用 ListCellRenderer 文档中的示例代码作为自定义列表单元格呈现器的起点。

当我运行该示例时,您可以看到第一个列表条目中的 HTML 是呈现的,而不是被解释的。

JList Custom Renderer