【问题标题】:Java AffineTransform working differently on different systemsJava AffineTransform 在不同系统上的工作方式不同
【发布时间】:2021-01-21 14:08:44
【问题描述】:

我已经开始使用AffineTransform 来旋转我正在使用Graphics2D 绘制的文本,我注意到它有时会正常工作,而有时当我刚刚意识到它在我的 Windows 7 上始终按预期工作时却不行PC,但从来没有在我的 Windows 10 笔记本电脑上。

我在两个系统上都使用 Java 15.0.1。

这里有一个小测试用例来说明我的观点:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;

public class AffineTransformTest extends JPanel {
    
    private static final int SIZE = 40;
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        int centerX = getWidth()/2;
        int centerY = getHeight()/2;
        
        g2.setColor(Color.BLACK);
        g2.drawRect(centerX - SIZE/2, centerY - SIZE/2, SIZE, SIZE);
        
        AffineTransform at = g2.getTransform();
        at.setToRotation(Math.toRadians(45),centerX, centerY);
        g2.setTransform(at);
        g2.setColor(Color.RED);
        g2.drawRect(centerX - SIZE/2, centerY - SIZE/2, SIZE, SIZE);
    }
    
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        AffineTransformTest test = new AffineTransformTest();
        frame.setContentPane(test);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300,300);
        frame.setVisible(true);
    }
}

黑色矩形是位于JPanel 中间的常规矩形。 红色矩形是在旋转 45° 后绘制的,应该与黑色矩形共享同一个中心(如第一张图片所示)。

但是,我的笔记本电脑会产生第二张图片中显示的结果。

Expected result - Windows 7 | Incorrect result - Windows 10

这怎么可能?

【问题讨论】:

    标签: java affinetransform


    【解决方案1】:

    这可能是因为您违反了 Javadoc 规定的 paintComponent() 方法的约定

    如果你在子类中覆盖它,你不应该永久化 更改传入的图形。例如,你不应该改变 剪辑矩形或修改变换。如果你需要做这些 您可能会发现从 传入 Graphics 并对其进行操作。

    因此,Windows 7 和 Windows 10 原生 UI 实现之间的细微差别可能就是其中一个中断而另一个不中断的原因。

    要查看这是否确实是原因,请尝试将行 Graphics2D g2 = (Graphics2D)g; 更改为 Graphics2D g2 = (Graphics2D)g.create();,这将克隆 Graphics 对象并保持原始对象不变。

    编辑以澄清正确答案: 该问题是由at.setToRotation 调用在绘制黑色正方形之后和绘制旋转的红色正方形之前清除图形上下文上的默认缩放变换引起的。推荐的解决方案是直接在保留现有比例变换的Graphics2D 对象上调用方法的rotate(theta,x,y) 形式。

    【讨论】:

    • 我原本以为我可能想要获得原始的 AffineTransform 并将其放在一边,然后再将其设置为 Graphics,以便我可以将其重新设置以恢复它。可悲的是,这并没有帮助。我会试试你的方法,然后告诉你。
    • 因此使用(Graphics2D)g.create(); 创建了副本,但没有更改。看起来完全一样。
    • 你的Win10笔记本电脑有没有高DPI显示?如果是这样,at.setToRotation 调用可能会清除图形上下文中的初始缩放变换,从而导致这种奇怪的行为。在任何情况下,最好的做法是使用g2.rotate(Math.toRadians(45),centerX, centerY) 而不是直接操作 AffineTransform。
    • 您似乎完全正确!我确实将我的 Windows 10 UI 缩放到 125% 我将其设置回 100% 以查看它是否确实是原因,并且确实如此。我也没有意识到Graphics2D 包含旋转方法。这就是我这样做的原因。我确实想知道原来的方法不起作用还是一个错误,但无论如何我保留了(Graphics2D)g.create(); 部分并使用了Graphics2D.rotate 方法,它终于可以正常工作了!非常感谢!
    猜你喜欢
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 2014-02-06
    • 2018-10-16
    • 1970-01-01
    • 2018-12-11
    相关资源
    最近更新 更多