Bug还是特性:Swing默认GUI字体在Win6+下不正确

18

刚刚(令人惊讶的)发现了我在Win6+机器上看到应用程序看起来如此拥挤的原因(Vista和Win7同样如此,均使用120dpi设置,jdk6和jdk7):从桌面属性中查找的控件字体具有错误的字体族和错误的大小:

public static void main(String[] args) {
    Font guiFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty("win.defaultGUI.font");
    int guiSize = guiFont.getSize();
    Font iconFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty("win.icon.font");
    System.out.println("gui default: " + guiFont + "\nicon default: " + iconFont);
}

输出:

gui default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=13]
icon default: java.awt.Font[family=Segoe UI,name=Segoe UI,style=plain,size=15] 
后者几乎用于所有文本的本机应用程序,而Swing使用前者...
问题:
- 这可能有什么原因,还是只是一个错误? - 负责人是谁:Swing查找(从相关系统资源中读取desktopProperty)还是操作系统没有正确报告它? - 如何强制使用后者?
解决最后一个选项:
- 对于完全控制LAF的用户,可以考虑设置所有相关文本字体(这就是JGoodies所做的,分解为FontPolicy/Set)。 - 一种肮脏的hack是将defaultGUI桌面属性的值设置为正确的值 - 它涉及反射访问工具包,自然会在受安全限制的上下文中出现问题。 - ??
编辑
以防万一有人感兴趣,这是肮脏的hack:
/**
 * Replaces the default gui desktop font property with the icon font
 * if the former is smaller.
 * 
 */
public static void ensureDefaultGUIFontSize() {
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    Font guiFont = (Font) toolkit.getDesktopProperty("win.defaultGUI.font");
    Font iconFont = (Font) toolkit.getDesktopProperty("win.icon.font");
    if (guiFont.getSize() < iconFont.getSize()) {
        invokeDeclaredMethod("setDesktopProperty", Toolkit.class, 
            toolkit, "win.defaultGUI.font", iconFont);
    }
}

private static void invokeDeclaredMethod(String methodName,
        Class<?> clazz, Object instance, String propertyName,
        Object propertyValue) {
    try {
        Method method = clazz.getDeclaredMethod(methodName, String.class, Object.class);
        method.setAccessible(true);
        method.invoke(instance, propertyName, propertyValue);
    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        LOG.finer("forcing desktop property failed " + e.getStackTrace());
    }

}

编辑2

澄清一下:这个hack只对WindowsLAF有效。Nimbus完全忽略系统设置,Metal部分忽略:后者的字体始终为Dialog,只有大小从desktopProperties中获取。听起来很好,但实际上不是:主要字体的映射相当奇怪,例如常用的controlFont大小设置为“win.ansiVar.font.height”(这是什么遗留物?),在我的机器上是13…

编辑3

即使在Windows界面中,这个hack也有局限性,例如@Walter的评论中提到的:

当您缩放Windows UI时,此错误特别明显。打开JFileChooser会还原这个hack。此外,JTree/JTable行高度不会自动更新为新的字体大小,您还需要调整图标的大小。


http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4950968 - 猜测解决方法在新的Windows上不起作用。 - Walter Laan
@WalterLaan 嗯...那个旧的解决方法不应该被替换吗?它甚至在 MS Sans vs. Tahoma bug 之前就存在了:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5079742。我能找到的最新的是 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6436509,但已经被标记为无法重现(确实,因为0/null已经消失了,但现在没有返回正确的值...) - kleopatra
2
建议改用OS X而不是Windows可能并不有帮助 :-) - Robin
1
当你缩放Windows UI时,这个bug特别明显。顺便说一下,打开JFileChooser会恢复hack。此外,JTree/JTable行高不会自动更新为新的字体大小,你还需要缩放你的图标。@kleopatra,你是否已经提交了官方的bug报告? - Walter Laan
@WalterLaan 谢谢你的警告!我没有,我的内部渠道干涸了...正常的路线也无法使用。 - kleopatra
显示剩余2条评论
1个回答

5
我认为这不是Win7和内置主题的错误,而是其基本属性之一。字体的大小很有趣,我仍然使用较小的字体(默认设置来自OS安装)。
例如,如果我设置/切换
1. Windows7基本主题
gui default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]
icon default: java.awt.Font[family=Segoe UI,name=Segoe UI,style=plain,size=12]

2. Windows 7经典主题

gui default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]
icon default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]

don't touched the Font property, will be continue for from WinXP

3. Windows XP 修改主题

gui default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]
icon default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=13]

4. Windows 7经典主题

gui default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]
icon default: java.awt.Font[family=Tahoma,name=Tahoma,style=plain,size=11]

感谢测试 :-) 对于所有非经典主题,默认本地字体为SegoeUI,我个人认为(请参见UXGuide,PDF版本在http://www.microsoft.com/en-us/download/details.aspx?id=2695),实际上当我将原生应用程序中的文本与强制使用Segoe的Swing文本进行比较时,这是可见的。 - kleopatra

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