刚刚(令人惊讶的)发现了我在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行高度不会自动更新为新的字体大小,您还需要调整图标的大小。