如何在 Swing 中逐渐旋转图像? [英] How to rotate an image gradually in Swing?

查看:71
本文介绍了如何在 Swing 中逐渐旋转图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户单击按钮时,我正在旋转图像.但它不起作用.

I have an image I am rotating when the user clicks on a button. But it is not working.

我想看到图像逐渐旋转到 90 度直到它停止,但它没有.单击按钮时,图像必须逐渐旋转 90 度.

I would like to see the image rotating gradually to 90 degrees till it stops but it doesn't. The image must rotate 90 degrees gradually when the button is clicked.

我创建了一个 SSCCE 来演示这个问题.请将 CrossingPanelSSCE 类中的图像替换为您选择的任何图像.只需将图像放在您的 images 文件夹中并将其命名为 images/railCrossing.JPG.

I have created an SSCCE to demonstrate the problem. Please replace the image in the CrossingPanelSSCE class with any image of your choice. Just put the image in your images folder and name it images/railCrossing.JPG.

RotateButtonSSCE

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;

public class RotateButtonSSCE extends JPanel implements ActionListener{
      private JButton rotate = new JButton("Rotate");
      private VisualizationPanelSSCE vis = new VisualizationPanelSSCE();

    public RotateButtonSSCE() {
        this.setBorder(BorderFactory.createTitledBorder("Rotate Button "));
        this.rotate.addActionListener(this);
        this.add(rotate);
    }

    public void actionPerformed(ActionEvent ev) {
        vis.rotatetheCrossing();
    }

}

CrossingPanelSSCE

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class CrossingPanelSSCE  extends JPanel{

    private static final long serialVersionUID = 1L;

    // private data members
     private Image crossingImage;
     private int currentRotationAngle;
     private int imageWidth;
     private int imageHeight;
     private AffineTransform affineTransform;
     private boolean clockwise; 
     private static int ROTATE_ANGLE_OFFSET = 2;

     private int xCoordinate;
     private int yCoordinate;

     private static javax.swing.Timer timer;

     private void initialize(){
         this.crossingImage = Toolkit.getDefaultToolkit().getImage("images/railCrossing.JPG");
         this.imageWidth = this.getCrossingImage().getWidth(this);
         this.imageHeight = this.getCrossingImage().getHeight(this);
         this.affineTransform = new AffineTransform();
         currentRotationAngle = 90;
         timer = new javax.swing.Timer(20, new MoveListener());
     } 

    public CrossingPanelSSCE(int x, int y) {
        this.setxCoordinate(x);
        this.setyCoordinate(y);
        this.setPreferredSize(new Dimension(50, 50));
        this.setBackground(Color.red);
        TitledBorder border = BorderFactory.createTitledBorder("image");
        this.setLayout(new FlowLayout());
        this.initialize();

    }


    public void paintComponent(Graphics grp){ 

        Rectangle rect = this.getBounds();
        Graphics2D g2d = (Graphics2D)grp;
        g2d.setColor(Color.BLACK);
        this.getAffineTransform().setToTranslation(this.getxCoordinate(), this.getyCoordinate());

          //rotate with the rotation point as the mid of the image
        this.getAffineTransform().rotate(Math.toRadians(this.getCurrentRotationAngle()), this.getCrossingImage().getWidth(this) /2, 
                                         this.getCrossingImage().getHeight(this)/2);

        //draw the image using the AffineTransform
        g2d.drawImage(this.getCrossingImage(), this.getAffineTransform(), this);
    }


    public  void rotateCrossing(){
        System.out.println("CurrentRotationAngle: " + currentRotationAngle);
        this.currentRotationAngle += ROTATE_ANGLE_OFFSET;
        //int test = currentRotationAngle % 90;
        if(currentRotationAngle % 90 == 0){
         setCurrentRotationAngle(currentRotationAngle);
         timer.stop();           
        }

         //repaint the image panel
         repaint(); 
    }


    void start() {
        if (timer != null) {
            timer.start();
        }
    }


     private class MoveListener implements ActionListener {

            public void actionPerformed(ActionEvent e) {
               rotateCrossing();
        }

     }

    public Image getCrossingImage() {
        return crossingImage;
    }
    public void setCrossingImage(Image crossingImage) {
        this.crossingImage = crossingImage;
    }

    public int getCurrentRotationAngle() {
        return currentRotationAngle;
    }
    public void setCurrentRotationAngle(int currentRotationAngle) {
        this.currentRotationAngle = currentRotationAngle;
    }

    public int getImageWidth() {
        return imageWidth;
    }
    public void setImageWidth(int imageWidth) {
        this.imageWidth = imageWidth;
    }

    public int getImageHeight() {
        return imageHeight;
    }
    public void setImageHeight(int imageHeight) {
        this.imageHeight = imageHeight;
    }

    public AffineTransform getAffineTransform() {
        return affineTransform;
    }
    public void setAffineTransform(AffineTransform affineTransform) {
        this.affineTransform = affineTransform;
    }

    public boolean isClockwise() {
        return clockwise;
    }
    public void setClockwise(boolean clockwise) {
        this.clockwise = clockwise;
    }

    public int getxCoordinate() {
        return xCoordinate;
    }
    public void setxCoordinate(int xCoordinate) {
        this.xCoordinate = xCoordinate;
    }

    public int getyCoordinate() {
        return yCoordinate;
    }
    public void setyCoordinate(int yCoordinate) {
        this.yCoordinate = yCoordinate;
    }

    public javax.swing.Timer getTimer() {
        return timer;
    }
    public void setTimer(javax.swing.Timer timer) {
        this.timer = timer;
    }



}

VisualizationPanelSSCE

import gui.CrossingPanel;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;

import application.Robot2;

public class VisualizationPanelSSCE extends JPanel{


        //private data members
        private GeneralPath path;
        private Shape horizontalRail;
        private Shape verticalRail;
        private static int LENGTH = 350;
        private CrossingPanelSSCE crossingP;



         private void initializeComponents(){
             this.path = new GeneralPath();
             this.horizontalRail = this.createHorizontalRail();
             this.verticalRail = this.createVerticalRail();
             this.crossingP = new CrossingPanelSSCE(328,334);
         }

        public VisualizationPanelSSCE(){ 
            this.initializeComponents();
            this.setPreferredSize(new Dimension(400,400));
             TitledBorder border = BorderFactory.createTitledBorder("Rotation");
             this.setBorder(border);

        }

        public GeneralPath getPath() {
            return path;
        }
        public void setPath(GeneralPath path) {
            this.path = path;
        }


        private Shape createHorizontalRail(){
            this.getPath().moveTo(5, LENGTH);
            this.getPath().lineTo(330, 350);
            this.getPath().closePath();
            return this.getPath();
        }

        private Shape createVerticalRail(){
            this.getPath().moveTo(350, 330);
            this.getPath().lineTo(350,10);
            this.getPath().closePath();
            return this.getPath();
        }


        public void paintComponent(Graphics comp){
             super.paintComponent(comp); 
            Graphics2D comp2D = (Graphics2D)comp;
            BasicStroke pen = new BasicStroke(15.0F, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND);

            comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                    RenderingHints.VALUE_ANTIALIAS_ON);
            comp2D.setPaint(Color.black);
            comp2D.setBackground(Color.WHITE);
            comp2D.draw(this.horizontalRail);
            this.crossingP.paintComponent(comp2D);
        }


        public CrossingPanelSSCE getCrossingP() {
            return crossingP;
        }
        public void setCrossingP(CrossingPanelSSCE crossingP) {
            this.crossingP = crossingP;
        }

        public void rotatetheCrossing(){

             Runnable rotateCrossing1 = new Runnable(){  
                public void run() {
                  crossingP.start();
              }
          };
            SwingUtilities.invokeLater(rotateCrossing1);
        }


    }

TestGUISSCE 它包含主要方法.

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;

import javax.swing.*;

public class TestGUISSCE{
    private RotateButtonSSCE rotate = new RotateButtonSSCE();
    private VisualizationPanelSSCE vision = new VisualizationPanelSSCE();

    public void createGui(){

         JFrame frame = new JFrame("Example");
         frame.setSize(new Dimension(500, 500));


         JPanel pane = new JPanel();
         pane.add(this.vision);
         pane.add(rotate);  
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.add(pane);
         frame.setVisible(true);

    }

    public static void main(String[] args) {
        new TestGUISSCE().createGui();
    }
}

推荐答案

除了@tulskiy 的有用意见,我还要补充两点:

In addition to @tulskiy's helpful observations, I would add two points:

  1. 始终在 事件调度线程上构建您的 GUI,如下图.

sscce 应该是简短、独立、正确(可编译)的示例.为方便起见,不要要求他人重新创建多个公共类;使用顶级(包私有)或嵌套类.由于这是一个图形问题,请使用反映您的问题的公开或合成图像.

An sscce should be a Short, Self Contained, Correct (Compilable), Example. As a convenience, don't require others to recreate multiple public classes; use top-level (package-private) or nested classes. As this is a graphics problem, use a public or synthetic image that reflects your problem.

在下面的示例中,paintComponent() 更改图形上下文的变换以实现旋转.请注意,这些操作是按照声明顺序的(明显)相反的顺序执行的:首先,图像的中心被平移到原点;第二,图像被旋转;第三,图像的中心被平移到面板的中心.您可以通过调整面板大小来查看效果.

In the example below, paintComponent() alters the graphics context's transform to effect the rotation. Note that the operations are performed in the (apparent) reverse of the declaration order: First, the image's center is translated to the origin; second, the image is rotated; third, the image's center is translated to the center of the panel. You can see the effect by resizing the panel.

附录:另请参阅使用 AffineTransform 的替代方法.

Addendum: See also this alternative approach using AffineTransform.

package overflow;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;

/**
 * @see https://stackoverflow.com/questions/3371227
 * @see https://stackoverflow.com/questions/3405799
 */
public class RotateApp {

    private static final int N = 3;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setLayout(new GridLayout(N, N, N, N));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                for (int i = 0; i < N * N; i++) {
                    frame.add(new RotatePanel());
                }
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}


class RotatePanel extends JPanel implements ActionListener {

    private static final int SIZE = 256;
    private static double DELTA_THETA = Math.PI / 90;
    private final Timer timer = new Timer(25, this);
    private Image image = RotatableImage.getImage(SIZE);
    private double dt = DELTA_THETA;
    private double theta;

    public RotatePanel() {
        this.setBackground(Color.lightGray);
        this.setPreferredSize(new Dimension(
            image.getWidth(null), image.getHeight(null)));
        this.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                image = RotatableImage.getImage(SIZE);
                dt = -dt;
            }
        });
        timer.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
        g2d.rotate(theta);
        g2d.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
        g2d.drawImage(image, 0, 0, null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        theta += dt;
        repaint();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(SIZE, SIZE);
    }

}

class RotatableImage {

    private static final Random r = new Random();

    static public Image getImage(int size) {
        BufferedImage bi = new BufferedImage(
            size, size, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = bi.createGraphics();
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setPaint(Color.getHSBColor(r.nextFloat(), 1, 1));
        g2d.setStroke(new BasicStroke(size / 8));
        g2d.drawLine(0, size / 2, size, size / 2);
        g2d.drawLine(size / 2, 0, size / 2, size);
        g2d.dispose();
        return bi;
    }
}

这篇关于如何在 Swing 中逐渐旋转图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆