Java AffineTransform 在不同系统上的工作方式不同

Java AffineTransform working differently on different systems

我已经开始使用 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

怎么会这样?

这可能是因为您违反了 paintComponent() 方法的约定,其中 Javadoc 指出

If you override this in a subclass you should not make permanent changes to the passed in Graphics. For example, you should not alter the clip Rectangle or modify the transform. If you need to do these operations you may find it easier to create a new Graphics from the passed in Graphics and manipulate it.

所以 Windows 7 和 Windows 10 的 UI 本机实现之间的细微差别可能是一个中断而另一个不中断的原因。

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

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