Swing中无法呈现Unicode字符,实际使用的是什么字体?

4
我在我的Swing应用程序中显示Unicode字符时遇到了问题。我认为问题出在使用的字体上,该字体不包含适合中文语言的字符。(仅显示空框)。
以下是有关我的问题的更多信息(我进行了一些调查):
Linux(Kubuntu 14.04): 当我使用JAVA 6启动我的程序时,中文字符没有显示(仅显示空框)。(通过getFont()询问标签字体返回:DejaVu Sans)。 当我使用JAVA 7启动我的程序时,中文字符正确显示!(通过getFont()询问标签字体返回:DejaVu Sans)。
Windows(8.1): 当我使用JAVA 6启动我的程序时,中文字符正确显示!(通过getFont()询问标签字体返回:SansSerif)。 当我使用JAVA 7启动我的程序时,中文字符正确显示!(通过getFont()询问标签字体返回:SansSerif)。 $JAVA_HOME/lib/fonts(似乎作为回退字体使用),两个Java版本(6+7)都包含相同的字体。(在两个系统上) 字体文件大小相同(Java6 + Java7),fontconfig.properties.src也完全相同。
当我直接询问标签(通过getFont())时,在Windows(8.1)上返回“SansSerif”,在我的Kubuntu(14.04)上返回“DejaVu Sans”。(请参阅屏幕截图)
在Linux上使用JAVA 6启动: enter image description here 在Linux上使用JAVA 7启动: enter image description here 在Windows上的“SansSerif”正确显示字符,但是使用了哪个SansSerif字体? MS SansSerif(唯一带有SansSerif名称的字体)并没有所有这些中文字符。
编辑: DejaVu Sans也是如此。 看起来DejaVu Sans没有中文字符!(但是它们被显示!)
编辑2: 我尝试了Andrew发布的代码(请参见:How to determine if 2 fonts have equivalent glyphs?),但使用中文示例文本时,结果如下:

编辑3:
按照要求,以下是我测试过的字符串:

String s = "\u6253\u5370\u8FC7\u671F\u8BC1\u4E66\u8BB0\u5F55"; //means: 打印过期证书记录
JOptionPane.showMessageDialog(null, s);

问题是:
系统上实际使用的字体是哪种,如何找到?
谢谢。


我不确定你问题的答案。但是,为了找到可以显示该字符串的字体,我建议检查Font.canDisplayUpTo(String) - Andrew Thompson
谢谢您的建议,但使用 Font.canDisplay... 我无法找出使用的是哪种字体。 - Ben
你没有提供任何方法来找出使用了哪种字体。你只是建议如何找出字体是否能够显示文本。除此之外,我不会将我的问题分成两个问题(以免在StackOverflow上垃圾信息)。相反,我会删除我的第二个问题,这样像你这样的人就不会有问题了。然后我会自己找出答案。(即使这显然是我的问题的一部分) - Ben
"我尝试了你的代码。强烈建议使用对话框中看到的中文文本显式地进行尝试。由于我不知道创建该文本所需的代码点,因此无法在此处测试它。" - Andrew Thompson
只是一个快速的更新。我在Windows上尝试了中文文本。JTextField显示了这些字符。检查文本字段中使用的字体显示为“Dialog plain”。当我询问哪些字体可以提供相同的字符形状时,软件显示了一个长列表(与英语句子通常只有2或3个不同)。大多数列出的字体都是逻辑字体,剩下的3个是“MingLiU”,“MingLiU_HKCS”或“PMingLiU”。 - Andrew Thompson
显示剩余6条评论
2个回答

5

这是对我自己问题的回答。

我进行了更多的调查:
看起来,对于某些类型的语言(字符),使用特殊配置。

Linux和Solaris 11字体支持
在JDK中,逻辑字体历史上在fontconfig.properties文件中静态指定。然而,在各种Linux实现中,字体的存在不一致。因此,如果没有自定义文件,亚洲(CJK)文本等将无法呈现。在JDK 7中,在Linux上以及在Solaris 11上,在没有针对操作系统版本定制的fontconfig.properties文件的情况下,默认行为是使用系统libfontconfig选择要用于逻辑字体的字体。在这种情况下,逻辑字体将反映由使用相同平台库的Gnome / KDE桌面应用程序使用的字体。

这是我在这里找到的: http://docs.oracle.com/javase/7/docs/webnotes/adoptionGuide/

这意味着在Java 6和Java 7中选择正确的字体有所不同。
接下来,我检查了我的(Java 6)fontconfig文件,并找到以下内容(仅包含重要部分):

# 组件字体映射
allfonts.chinese-cn-iso10646=-arphic-ar pl uming cn-light-r-normal---%d---c--iso10646-1

# 字体文件名
filename.-arphic-ar_pl_uming_cn-light-r-normal---%d---c--iso10646-1=/usr/share/fonts/truetype/arphic/uming.ttc

# 搜索序列
sequence.allfonts=latin-1
sequence.allfonts.UTF-8.zh.CN=latin-1-cjk,chinese-cn-iso10646
sequence.allfonts.UTF-8.zh.TW=latin-1-cjk,chinese-tw-iso10646
sequence.allfonts.UTF-8.zh.HK=latin-1-cjk,chinese-hk-iso10646

当默认字体无法显示所需字符时,应使用指定的字体(这里是uming.ttc)。
之后,我检查了/usr/share/fonts/truetype/arphic/uming.ttc是否存在。
该字体/文件不存在
(我在三个不同的Ubuntu安装中进行了检查!)

我不知道为什么它没有被安装(但仍在Java字体配置中使用),但在执行以下操作后(在另一台计算机上,但出现了相同的问题):

  sudo apt-get install fonts-arphic-uming

为了安装缺失的字体,我再次测试(使用JAVA 6):

enter image description here

现在一切似乎都很好。

(我认为Nim的答案也是类似的方向,但它(在我看来)太笼统了。此外,Java并不真正“混合”和“匹配”字体。)


1
Java 7在Linux上使用fontconfig,因此它知道如何回退当字体缺少字形时。要检查给定系统上fontconfig使用的回退,可以使用fc-*命令(fc-match等)。
但是,您的jre可能会包括私有回退规则,除了系统规则(fontconfig*xml)。
您无法在java 6上模拟此行为,因为fontconfig不是简单的优先级列表,在任何给定时间只使用单个字体。它将根据显示文本的需求和应用程序表达的偏好(字体模式)混合和匹配字体。
启用fontconfig的软件将始终在系统上存在能够显示文本的一个字体的情况下工作。不使用fontconfig的应用程序将在硬编码在应用程序中的字体名称与可用字体不匹配时立即失败。在Linux系统上安装的字体有很大的变化,您不能指望在另一个安装中也存在一个字体(正是因为所有现代Linux应用程序都使用fontconfig并且不关心)。

"它会根据所需显示的文本混合和匹配字体"。很有趣。我已经开始怀疑这一点,但没有信息来证实它。 - Andrew Thompson
好的,但我有一些问题:**1.**:我没有使用任何自定义/非默认字体。 **2.**:我没有对默认(Java/Swing)配置进行任何更改。 **3.**:在Windows中,Java 6和Java 7之间显示中文字体没有问题。 - Ben
Windows字体列表往往非常统一,因为更改速度缓慢并受到Microsoft专有字体的限制。由于其桌面根源,因此默认安装可能会捆绑比Linux服务器更多的字体。因此,在此平台上,“使用硬编码字体列表”的Java 6方法不太可能导致错过。 (此外,Java 6是由SUN生产的,而SUN关心的唯一桌面平台是Windows,因为没有人再使用Solaris进行桌面操作,它永远不会承认Linux吃掉了它的蛋糕,并且SUN曾经提出了一个与fontconfig竞争的方案,但没有人采用)。 - nim
顺便提一下,在 SUN 停止管理后,Java 文本支持的现代化并未完成,fontconfig 是第一步,下一步是在 http://openjdk.java.net/projects/harfbuzz/ 上进行。在接下来的 Java 发布中,事情将再次发展。 - nim

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