Java Graphics2D rotate 方法导致之后绘制的所有东西都抖动

Java Graphics2D rotate method causes all things painted afterwards to jitter

我在使用 javas rotate 方法时遇到了一些问题。在下面的示例中,我首先调用 rotate 方法,绘制要旋转的矩形,然后在完全相反的方向再次调用 rotate 方法,因此以 0 度旋转绘制以下矩形。然而,之后绘制的所有东西似乎都有问题,因为第二个矩形经历了一些我只能描述为 y 轴上的抖动。这当然只会影响调用 rotate 方法后绘制的内容。非常感谢您的帮助,因为看起来真的很烦人。

package pack;

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test extends JFrame{

    private static final long serialVersionUID = 1L;
    public int degrees = 0;
    public Timer timer;

    public Test() {
        setVisible(true);
        setSize(400, 400);
        setContentPane(new paintLabel());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        timer= new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {degrees++;repaint();}
        });
        timer.start();
    }

    public class paintLabel extends JLabel {
        private static final long serialVersionUID = 1L;

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;

            g2d.rotate(Math.toRadians(degrees), 100, 185);
            g2d.fillRect(40, 125, 120, 120);
            g2d.rotate(-Math.toRadians(degrees), 100, 185);
            g2d.fillRect(225, 125, 120, 120);
        }
    }

    public static void main(String[] args) {new Test();}
}

如果你旋转得更慢,效果是可见的 - 很抱歉没有注意到旋转得更快

如果你画一个 Rectangle,那么矩形的所有点都会被变换然后绘制。这会导致 舍入问题 。如果你想锁定你的矩形,你必须使用固定比例的矩形,即Image!可以防止你抖动...

public class paintLabel extends JLabel {
    private static final long serialVersionUID = 1L;
    final Image img = createRectImage();

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.rotate(Math.toRadians(degrees), 100d, 185d);
//        g2d.fillRect(40, 125, 120, 120);
        g2d.drawImage(img, 40,125, null);
        g2d.rotate(-Math.toRadians(degrees), 100d, 185d);
        g2d.fillRect(225, 125, 120, 120);
    }
}
private Image createRectImage() {
    BufferedImage image = new BufferedImage(120,120, BufferedImage.TYPE_4BYTE_ABGR);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.RED);
    g.fillRect(0,0,120,120);
    return image;
}

比较输出!

这与精度无关,因为您没有旋转图像。您正在旋转 Graphics context。另一个图像没有旋转的原因是因为您只是将上下文返回到它之前的状态。然后你需要围绕第二张图片的中心旋转。

首先你做错了一些事情。

  • 不要扩展 JFrame(你没有覆盖任何东西,所以只使用一个实例);
  • 扩展 JPanel 并将其放入框架中
  • 将标签添加到面板
  • 覆盖 getPreferredSize 以调整 JLabel
  • 的大小

在这里试试这个。如果打开抗锯齿,抖动就会消失。它还倾向于平滑任何粗糙的边缘。另一个图像以相反的方向旋转。请注意,这可以在没有 JLabel class.

paintComponent 内部完成
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.renderable.RenderableImage;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test extends JPanel {
    JFrame f = new JFrame();
    private static final long serialVersionUID = 1L;
    public int degrees = 0;
    public Timer timer;

    public Test() {
        f.add(this);
        add(new PaintLabel());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        timer= new Timer(50,(ae)->{degrees++; repaint();});
        
        timer.start();
        f.pack();
        f.setLocationRelativeTo(null); //center on screen
        f.setVisible(true);
    }
    

    public class PaintLabel extends JLabel {
        private static final long serialVersionUID = 1L;
        
        
        public Dimension getPreferredSize() {
            return new Dimension(400,400);
        }
        
        @Override
      public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.BLUE);
            g2d.rotate(Math.toRadians(degrees), 100, 185);
            g2d.fillRect(40, 125, 120, 120);
            g2d.rotate(-Math.toRadians(degrees), 100, 185);
            g2d.fillRect(225, 125, 120, 120);
        }
    }

    public static void main(String[] args) {
        new Test();}
}