旋转后图像不在适当的位置(图形)

我试图以不同的速率显示直径为512untis的两个旋转轮,但我无法移除先前绘制的图像图形并将旋转的图形设置在正确的位置。 现在我正以任意角度进行旋转。 我尝试了affineTransform并获得了旋转,但奇怪的是所有像素都散开了。 我使用带有thread.sleep()的while循环。 以下是代码:// drawSmallCircle和drawBigCircle返回两个图像。

class MyFramePart2 extends JFrame { String name; JPanel big_obj_panel,small_obj_panel; JLabel bigLabel,smallLabel;BufferedImage imgRet,imgRetSmall; static double radians,angle,rev,fps,smallAngle,smallRadians; int numLines,i=0; MyFramePart2(String frameName,int numStrokes,double revolutions,double frameps) { numLines=numStrokes; smallAngle=smallRadians=angle=radians=Math.toRadians(360/numLines); rev=revolutions; fps=frameps; setSize(1240,720); setLocation(0,0); setLayout(null); getContentPane().setBackground(Color.WHITE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); big_obj_panel=new JPanel(); big_obj_panel.setLayout(null); big_obj_panel.setSize(512,512); big_obj_panel.setLocation(100,100); big_obj_panel.setBackground(Color.white); add(big_obj_panel); imgRet=drawBigCircle(); bigLabel = new JLabel(new ImageIcon(imgRet)); bigLabel.setLayout(null); bigLabel.setLocation(0,0); bigLabel.setSize(512,512); bigLabel.setOpaque(true); bigLabel.setBackground(Color.white); big_obj_panel.add(bigLabel); small_obj_panel=new JPanel(); small_obj_panel.setLayout(null); small_obj_panel.setSize(512,512); small_obj_panel.setLocation(700,100); small_obj_panel.setBackground(Color.white); add(small_obj_panel); imgRetSmall=drawSmallCircle(); smallLabel = new JLabel(new ImageIcon(imgRetSmall)); smallLabel.setLayout(null); smallLabel.setLocation(0,0); smallLabel.setSize(512,512); smallLabel.setOpaque(true); smallLabel.setBackground(Color.white); small_obj_panel.add(smallLabel); setVisible(true); while(i!=5) // suppose to be while true, just checking { setVisible(true); bigLabel.setIcon(new ImageIcon(imgRet)); smallLabel.setIcon(new ImageIcon(imgRetSmall)); try{ Thread.sleep(10); } catch(Exception e) {} i++; } } @Override public void paint(Graphics g) { super.paint(g); Graphics2D g2d=(Graphics2D)g; g2d.translate(256,256); g2d.rotate(Math.toRadians(20)); g2d.translate(-256,-256); g2d.drawImage(imgRet,0,0,null); g2d.dispose(); super.paint(g); g2d=(Graphics2D)g; g2d.translate(256,256); g2d.rotate(Math.toRadians(30)); g2d.translate(-256,-256); g2d.drawImage(imgRetSmall,0,0,null); g2d.dispose(); } public static BufferedImage drawBigCircle() { BufferedImage img=new BufferedImage(512,512,BufferedImage.TYPE_INT_ARGB); Graphics2D g2d=img.createGraphics(); g2d.setColor(Color.black); g2d.drawOval(0,0,511,511); Line2D l2d; while(angle <= 2*Math.PI) { l2d=new Line2D.Double(256,256,256+256*Math.cos(angle),256+256*Math.sin(angle)); g2d.draw(l2d); angle=angle+radians; } return img; } } 

Swing的第一条规则。 不要阻止事件调度线程。 这样做会使应用程序看起来像挂起并阻止EDT处理任何重绘请求。

这意味着,您需要一些方法来安排不阻止EDT的更新

Swing的第二条规则。 不要从EDT以外的任何线程创建或修改任何UI组件。

一般来说,你应该避免覆盖顶级容器的paint方法,如JFrame ,除了其他一切,它们不是双缓冲的,这意味着你的绘画会随着它的更新而闪烁。 相反,您应该使用其中一个Swing容器,例如JPanel

有很多不同的方法来实现这一目标。 基本上,在这里我使用了三个列表,但如果我是认真的,我会创建一个可以保持所有必需信息的对象(图像,角度和三角形)

为了实现实际动画,我使用了javax.swing.Timer 。 这将至少每n个时段触发一个事件,但更重要的是,它会在事件调度线程的上下文中执行。 这样可以确保对角度所做的所有更改都以防止在更新值时发生绘画的任何可能性的方式完成…

此示例以不同(随机)速度旋转三个图像…

在此处输入图像描述

 public class TestRotation { public static void main(String[] args) { new TestRotation(); } public TestRotation() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new AnimationPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class AnimationPane extends JPanel { private List images; private List angles; private List speed; public AnimationPane() { images = new ArrayList<>(5); images.add(createWheel(50, 4)); images.add(createWheel(50, 3)); images.add(createWheel(50, 6)); angles = new ArrayList<>(); speed = new ArrayList<>(); for (int index = 0; index < images.size(); index++) { angles.add(0d); speed.add(Math.random() * 5d); } Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (int index = 0; index < angles.size(); index++) { double angle = angles.get(index); double delta = speed.get(index); angle += delta; angles.set(index, angle); } repaint(); } }); timer.setRepeats(true); timer.setCoalesce(true); timer.start(); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int x = 0; int y = 0; for (int index = 0; index < images.size(); index++) { BufferedImage image = images.get(index); double angle = angles.get(index); // This is important. Basically we going to grab a isolated snap shot // of the current graphics context. This means any changes we make // will not affect the original graphics context (other then painting) Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); AffineTransform at = new AffineTransform(); at.translate(x, y); at.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2); g2d.setTransform(at); g2d.drawImage(image, 0, 0, this); g2d.dispose(); x += image.getWidth(); } } } protected Point2D calculateOutterPoint(int radius, double angel) { int x = Math.round(radius / 2); int y = Math.round(radius / 2); double rads = Math.toRadians((angel + 90)); // This determins the length of tick as calculate from the center of // the circle. The original code from which this derived allowed // for a varible length line from the center of the cirlce, we // actually want the opposite, so we calculate the outter limit first double fullLength = (radius / 2d); // Calculate the outter point of the line double xPosy = (x + Math.cos(rads) * fullLength); double yPosy = (y - Math.sin(rads) * fullLength); return new Point2D.Double(xPosy, yPosy); } public BufferedImage createWheel(int radius, int spokes) { BufferedImage img = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(Color.black); g2d.drawOval(0, 0, radius - 1, radius - 1); Point2D center = new Point2D.Double(radius / 2d, radius / 2d); double angle = 360d / spokes; for (int index = 0; index < spokes; index++) { Point2D p = calculateOutterPoint(radius, index * angle); g2d.draw(new Line2D.Double(center, p)); } g2d.dispose(); return img; } }