3

I am trying to simply rotate an image in a for loop like so:

class MyCanvas extends JComponent {

AffineTransform identity = new AffineTransform();
Image arrow;
Double angle = -180.0;

public void spin() {
    angle += 10.0;
    for(int i = 0; i < 10; i++) {
        repaint();
        System.out.println(i);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    arrow = Toolkit.getDefaultToolkit().getImage("red-arrow-right-th.png");
    // Rotate + translate
    AffineTransform trans = new AffineTransform();
    trans.setTransform(identity);
    trans.translate(getWidth()/2, getHeight()/2);
    trans.rotate(Math.toRadians(angle));
    System.out.println(trans);
    g2.drawImage(arrow, trans, this);
    g2.finalize();
}
}

However when I run call spin() in main, it appears to apply only a single rotation, whilst still printing out the loop correctly. What am I overlooking something?

Ortomala Lokni
  • 56,620
  • 24
  • 188
  • 240
chris
  • 4,840
  • 5
  • 35
  • 66
  • I would suggest using the rotate method that provides you the means to set the anchor point around which the rotation will occur. I think the rotation by default, is the top/position of the translation point... – MadProgrammer Mar 04 '15 at 10:34
  • 1- Don't override paint, override paintComponent; 2- Call super.paint/Component before performing any custom painting; 3- Never call finalise on anything and especially not on objects you didn't create yourself. Beware, Swing is not thread safe and you should never call anything that might block the event dispatching thread, consider using a Swing Timer instead – MadProgrammer Mar 04 '15 at 10:39

1 Answers1

1

I've transformed your code using the recommendation of MadProgrammer:

  • Don't override paint, override paintComponent.
  • Call super.paint before performing any custom painting,
  • Never call finalize on anything and especially not on objects you didn't create yourself.
  • Use a Swing Timer

Note the following

  • A qualified this is used to access the ImageRotationView instance from the ActionListener inner class.

  • AffineTransform.getRotateInstance returns a transform that rotates coordinates around an anchor point.

  • Speed can be optimized but it works correctly like this.
  • This class works as a standalone application
  • A file named dice.png should be present in the base directory.

.

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;


public class ImageRotationFrame {

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

    public ImageRotationFrame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Testing");
                frame.setSize(400, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new ImageRotationComponent());
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });

    }

    private class ImageRotationComponent extends JComponent {

        Image arrow;
        double angle = 0.0;

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            angle += 0.4;
            AffineTransform trans = AffineTransform.getRotateInstance(angle, getWidth() / 2, getHeight() / 2);
            ((Graphics2D) g).drawImage(arrow, trans, this);
        }

        public ImageRotationComponent() {
            try {
                arrow = ImageIO.read(new File("dice.png"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            int delay = 500; //milliseconds
            ActionListener taskPerformer = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt) {
                    ImageRotationComponent.this.repaint();
                }
            };
            new Timer(delay, taskPerformer).start();
        }
    }
}
Community
  • 1
  • 1
Ortomala Lokni
  • 56,620
  • 24
  • 188
  • 240