字体与系统字体冲突时Java JLabel HTML显示乱码

Posted

技术标签:

【中文标题】字体与系统字体冲突时Java JLabel HTML显示乱码【英文标题】:Java JLabel HTML display garbled when font conflicts with system font 【发布时间】:2016-03-02 10:11:54 【问题描述】:

已更新 - 问题现在以一种丑陋的方式解决了 - 但必须有正确的方法来解决吗?

当字体名称与系统上已安装的字体名称冲突时,我在 JLabel 中的 html 中以自定义字体呈现文本时遇到问题。

系统字体的格式不同(otf vs ttf),所以不出所料,文本是乱码。

GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont 的调用返回false 表示字体注册失败。所以我想问题是,有没有办法在不注册的情况下使用这种字体,或者在注册之前重命名它?

我现在已经通过编辑 ttf 文件并修改字体名称来解决我的问题,以使冲突极不可能发生,但我猜必须有适当的方法来处理这种情况。

package test;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
class MyComponent extends JPanel 
    Font font; String text;
    public MyComponent(Font f) font=f;
    public void initSwing()
    
        final String labelcontents = "<html><center>foo</center></html>";
        System.out.println(labelcontents);
        JLabel text = new JLabel(labelcontents);
        text.setFont(font);
        add(text,BorderLayout.CENTER);
    


@SuppressWarnings("serial")
public class TestApplet extends JApplet 
        public void init()
        
            Font mainFont = null;
            InputStream is = getClass().getResourceAsStream("fonts/Exo-Bold.ttf");
            try 
                mainFont = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(24f);
                System.out.println(mainFont.getName());
                boolean registered=GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(mainFont);
                System.out.println("registered "+registered);
             catch (FontFormatException e1) 
                e1.printStackTrace();
             catch (IOException e1) 
                e1.printStackTrace();
            

            final Container fframe = (JComponent)(getContentPane());
            final MyComponent component = new MyComponent(mainFont);

            Thread t = new Thread(new Runnable() 
                public void run()  try 

                    SwingUtilities.invokeAndWait(new Runnable() public void run() 
                        fframe.add(component);
                        component.initSwing();
                        fframe.revalidate();
                        fframe.repaint();
                    );

                 catch (Exception e) 
                    e.printStackTrace();
                 
            );
            t.start();
        

【问题讨论】:

上述代码中使用的 Exo-Bold 字体可以——例如——从1001freefonts.com/d/5755/exo.zip下载? 我现在不记得它的来源了,但它来自一个免费的字体集合 也许你可以分享你的字体文件?您是否看到默认字体存在同样的问题? 【参考方案1】:

很奇怪。当我在笔记本电脑上运行您的示例小程序时,输出看起来不错:

我已将此 zip file 与“Exo-Bold.ttf”文件一起使用,并且在 Windows 8.1 上使用 Java 8(Oracle JDK 版本 1.8.0_65)。

这是我运行的代码的改编版本:

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

@SuppressWarnings("serial")
class MyComponent extends JPanel 
    Font font; String text;
    public MyComponent(Font f) font=f;
    public void initSwing()
    
        final String labelcontents = "<html><center>foo</center></html>";
        System.out.println(labelcontents);
        JLabel text = new JLabel(labelcontents);
        text.setFont(font);
        add(text,BorderLayout.CENTER);
    


@SuppressWarnings("serial")
public class TestApplet extends JApplet 
    public void init()
    
        Font mainFont = null;

        try 
            //InputStream is = getClass().getResourceAsStream("fonts/Exo-Bold.ttf");
            InputStream is = new FileInputStream("C:/Freek/[...]/Exo-Bold.ttf");
            mainFont = Font.createFont(Font.TRUETYPE_FONT, is)
                           .deriveFont(Font.BOLD, 24f);
            is.close();
            System.out.println(mainFont.getName());
            boolean result = GraphicsEnvironment.getLocalGraphicsEnvironment()
                                                .registerFont(mainFont);
            System.out.println("Result registerFont: " + result);
         catch (FontFormatException e1) 
            e1.printStackTrace();
         catch (IOException e1) 
            e1.printStackTrace();
        

        final Container fframe = (JComponent)(getContentPane());
        final MyComponent component = new MyComponent(mainFont);

        Thread t = new Thread(new Runnable() 
            public void run()  try 

                SwingUtilities.invokeAndWait(new Runnable() public void run() 
                    fframe.add(component);
                    component.initSwing();
                    fframe.revalidate();
                    fframe.repaint();
                );

             catch (Exception e) 
                e.printStackTrace();
             
        );
        t.start();
    

【讨论】:

Windows 7 x64 上的 Java 1.8.66。您认为在系统上安装相同的字体(可能与 .otf)会导致问题吗? 可能与字体文件有关。需要说明的是:我没有安装字体,而是下载了它以便小程序可以使用它。 好的,请参阅更新 2。通过在第二台机器上复制问题,我设法解决了更多问题。如果我将 Exo Bold 安装为 opentype 字体,第二台机器也会出现乱码。即使再次卸载 Exo Bold,情况仍然如此。 再次更新。我通过将 ttf 资源中的字体重命名为一个不太可能与任何内容冲突的长而混乱的名称来解决了这个问题。感谢您的帮助,为了我自己的目的,我很高兴。为了未来的访问者,我知道这个解决方案是一个杂项,所以很想知道是否有更好的方法来做到这一点。因此,请考虑自己有权获得一些赏金,如果您或其他任何人可以提供更好的解决方案,他们可以拥有其余的! 好消息和kludge 是一个比没有解决方案更好的解决方案!一个小问题(不是导致问题的原因):根据JavaDocs of the Font.createFont 方法(对于 Java 7):“此方法不会关闭 InputStream。”所以我认为在创建字体后添加is.close();会很好。【参考方案2】:

也许文本包含带有字符集或类似字符的 HTML 命令。

String text1 = "<html><body>"
    + text.replace("&", "&amp;")
          .replace("<", "&lt;")
          .replace(">", "&gt;");
    + "</body></html>";

【讨论】:

好主意,但事实并非如此。它包含的唯一 html 是 &lt;br/&gt;。 (我希望它支持&lt;i&gt;,但上面的案例没有它)。

以上是关于字体与系统字体冲突时Java JLabel HTML显示乱码的主要内容,如果未能解决你的问题,请参考以下文章

java用啥方法设置label的字体

Java Swing JLabel、HTML 和自定义字体

java中怎么设置label的字体大小及颜色显示

在 Java 中检查文本的字体属性

Google Webfont 与本地字体冲突

如何在不使用 HTML 的情况下向 JLabel 添加换行符