Java 1.7(Windows版本)的文本抗锯齿存在问题

6

在Java 1.7(Windows)中,Swing组件的文本抗锯齿渲染提示似乎存在问题。设置KEY_ANTIALIASING和/或KEY_TEXT_ANTIALIASING不再影响JLabelJEditorPane等的显示 - 但实际上我需要在我的项目中使用不同的设置。

您可以通过下面这个测试程序比较Java 1.6(jdk1.6.0_45)和Java 1.7(jdk1.7.0_40)之间的不同行为:

左侧运行Java 1.6,右侧运行Java 1.7

左侧是Java 1.6,右侧是Java 1.7。第一列使用Graphics2D.drawString绘制,第二列使用JLabel。在Java 1.6中,渲染提示会影响JLabel的显示,而在Java 1.7中,所有JLabels都呈现相同的效果(除了使用小数度量的那个)。

您知道如何在Java 1.7中使抗锯齿提示影响Swing组件吗?

测试程序:

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

    public class AntialiasMain extends JFrame {
    public AntialiasMain() {
        JPanel panel = new JPanel(new GridLayout(0, 1));
        panel.add(new AntialiasLabel("default", null));

        HashMap<Key, Object> hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        panel.add(new AntialiasLabel("AA off", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("AA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        panel.add(new AntialiasLabel("TextAA off", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("TextAA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("AA+TextAA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        panel.add(new AntialiasLabel("AA+FracMetr on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        panel.add(new AntialiasLabel("AA+TextLCD on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        panel.add(new AntialiasLabel("TextLCD on", hints));

        getContentPane().add(panel);

    }

    class AntialiasLabel extends JLabel {
        private final HashMap<Key, Object>  hints;
        private final String                label;

        private static final String         PALYNDROME          = "The quick brown fox jumped over the lazy dog";

        public AntialiasLabel(String label, HashMap<Key, Object> hints) {
            super(PALYNDROME);
            setForeground(Color.BLACK);
            setBorder(BorderFactory.createEmptyBorder(10, 150, 10, 10));
            this.label = label;
            this.hints = hints;
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            if (hints != null)
                g2.setRenderingHints(hints);
            g2.drawString("Setting: " + label, 2, getHeight() / 2 + 5);
            super.paintComponent(g2);
        }
    }

    public static void main(final String[] args) {
        JFrame f = new AntialiasMain();
        f.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

编辑: 系统属性 swing.aatextawt.useSystemAAFontSettings 没有效果。更改 外观和感觉(Look and Feel) 也没有作用。


1
你能尝试使用另一个外观和感觉的代码吗? - StanislavL
好主意。Nimbus、Metal、Windows和Substance都能得到相同的结果。 - sina72
3个回答

4

这个答案中找到了解决方案。请使用以下代码更新您的问题:

private static final Object AA_TEXT_PROP = getAaTextProperty();

public static Object getAaTextProperty() {

    Object aatext = null;
    try {
        Class<?> c = Class.forName("sun.swing.SwingUtilities2");
        Field f = c.getField("AA_TEXT_PROPERTY_KEY");
        aatext = f.get(null);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return aatext;
}
...

public AntialiasLabel(String label, HashMap<Key, Object> hints) {
    super(PALYNDROME);
    putClientProperty(AA_TEXT_PROP, null);
    ...
}

在Java 1.7 Windows上进行了测试。请注意,最近(2015年2月)的Windows更新,如kb3013455,已经破坏了许多系统上的字体反锯齿效果。


是的,这似乎有效。经过1.5年...恭喜! - sina72
或者简单地说:putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY,null); 同时它在Java 9中不再起作用。 - ron190

1

首先,关于Swing组件的行为有几点需要注意:

  • 当你调用super.paintComponent()时,Swing组件的UI代理可以设置任何渲染提示 - 看起来,从外观的JLabel中获得的UI代理重写了你的
  • 如果你不想使用反走样(即,你正在使用远程X或类似技术),你应该使用MetalLookAndFeel,因为它是针对这种情况设计的。
  • 不能保证任何组件的UI代理不会覆盖您设置的任何渲染提示 - 也就是说,您看到的行为是完全合法的

话虽如此,从JDK 1.6开始(因此据我所知,1.7也是如此,但不保证),你可以通过一个未记录(因此不受支持)的桌面属性访问AWT和Swing使用的默认渲染提示:

(Map<RenderingHints.Key, Object>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"));

这是我为NetBeans写的一个使用示例(大约在2004年左右),请参见getHints()方法。它的作用与您所需的相反,因为它试图强制抗锯齿开启。但是,操作该Map的内容或替换它可能会全局改变抗锯齿设置。

谢谢。StanislavL已经在上面的评论中建议过了。更改L&F并不能帮助解决问题(请尝试运行上面的示例代码;先使用1.7,然后再与1.7进行比较)。 - sina72
我已经得到了地图,但它已经包含了正确的提示;Motif LAF只是忽略了它 ☹ - mirabilos

0

我知道这是一个古老的问题,但我遇到了同样的问题。

经过调查,我发现如果在main()方法中添加以下代码,代码将按预期工作:

System.setProperty("awt.useSystemAAFontSettings","off");
System.setProperty("swing.aatext", "false");

看起来Java 7的默认设置从两个属性都为“关闭”变成了两个属性都为“开启”


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