使用Swing和Graphics2D在Java中旋转滚轮?

时间:2015-04-16 23:10:57

标签: java swing rotation

我正在开设一个可以围绕中心旋转轮子的课程。轮子是使用graphics2d创建的,但我无法弄清楚如何让轮子围绕中心旋转。 目前,车轮旋转,但不完全是原点。

我的最终目标是创造轮子,使其成为多色的,以及围绕它的程序,但我的主要关注点是让旋转轮工作。如果你能指出我正确的方向,我将永远感激不尽!

这是我目前的代码:

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


public class RotateApp {

private static final int N = 3;

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

        public void run() {
            JFrame frame = new JFrame();
            frame.setLayout(new GridLayout(N, N, N, N));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new RotatePanel());
            frame.pack();
            frame.setVisible(true);
            System.out.println();
        }
    });
}
}


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();
}


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);
}

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(10.0f));
    g2d.draw(new Line2D.Double(0, 100, 100, 100));
    g2d.draw(new Line2D.Double(100, 100, 200, 100));

    g2d.draw(new Line2D.Double(100, 0, 100, 100));
    g2d.draw(new Line2D.Double(100, 100, 100, 200));

    g2d.draw(new Line2D.Double(25, 25, 100, 100));
    g2d.draw(new Line2D.Double(100, 100, 175, 175));

    g2d.draw(new Line2D.Double(175, 25, 100, 100));
    g2d.draw(new Line2D.Double(100, 100, 25, 175));

    g2d.draw(new Ellipse2D.Double(0, 0, 200, 200));
    g2d.dispose();
    return bi;
}
}

2 个答案:

答案 0 :(得分:3)

您可以使用Rotated Icon类为您进行旋转,这样您就不必担心所有旋转逻辑,并且旋转逻辑位于可重用的类中。

使用此类的一个示例是:

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;

public class Rotation4 extends JPanel
{
    private JLabel label;
    private Icon icon;
    private Icon rotated;
    private int degrees;

    public Rotation4(Image image)
    {
        icon = new ImageIcon( image );
        label = new JLabel(icon);
        label.setPreferredSize( label.getPreferredSize() );
        add( label );
        setDegrees( 0 );
    }

    public void setDegrees(int degrees)
    {
        this.degrees = degrees;
        double radians = Math.toRadians( degrees );
        rotated = new RotatedIcon(icon, degrees);
        label.setIcon(rotated);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                Image bi = RotatableImage.getImage(210);
                final Rotation4 r = new Rotation4(bi);

                    final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
                    slider.addChangeListener(new ChangeListener()
                    {
                        public void stateChanged(ChangeEvent e)
                        {
                            int value = slider.getValue();
                            r.setDegrees( value );
                        }
                    });

                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new JScrollPane(r));
                f.add(slider, BorderLayout.SOUTH);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    static 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(10.0f));

            g2d.draw(new Line2D.Double(5, 105, 205, 105));
/*
            g2d.draw(new Line2D.Double(100, 100, 200, 100));

            g2d.draw(new Line2D.Double(100, 0, 100, 100));
            g2d.draw(new Line2D.Double(100, 100, 100, 200));

            g2d.draw(new Line2D.Double(25, 25, 100, 100));
            g2d.draw(new Line2D.Double(100, 100, 175, 175));

            g2d.draw(new Line2D.Double(175, 25, 100, 100));
            g2d.draw(new Line2D.Double(100, 100, 25, 175));
*/
            g2d.draw(new Ellipse2D.Double(5, 5, 199, 199));

            g2d.setColor(Color.BLACK);
            g2d.fillOval(100, 100, 10, 10);

            g2d.dispose();
            return bi;
        }
    }
}

注意我还必须对您的图像和绘画进行更改。无论您是使用RotatedIcon还是自己执行旋转代码,都需要进行以下更改:

  1. 图像尺寸更改为210.这是因为您的笔触大小为10,因此您需要考虑圆形轮廓中的额外像素。

  2. 您需要将圆的原始尺寸改为笔划尺寸的一半。所以在这种情况下,原点变为(5,5)。

  3. 椭圆的大小需要更改为199.这是因为椭圆的轮廓被绘制的方式。轮廓需要1个额外的像素。如果将尺寸保留为200,则轮廓的1个像素将丢失。当使用10的笔触大小时,这不是很明显,但如果你使用1的大小,那么右边和底边都会缺少轮廓。

  4. 您的行的位置需要更改。你不希望线条直接到圆的边缘,因为那样你将在边缘处得到一条扁平线而不是圆形线。所以我开始从开始的5个像素的行,并结束它从结束5像素。

答案 1 :(得分:2)

好的,通过少量修改和更少的“辐条”,我让你的车轮旋转为中心(1.)和多色(2。):


更新1.)要在(原始)代码中进行中心旋转,只需将SIZE变为200!

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;

public class RotateApp {

    private static final int N = 3;

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            JFrame frame = new JFrame();
            frame.setLayout(new GridLayout(N, N, N, N));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new RotatePanel());
            frame.pack();
            frame.setVisible(true);
            System.out.println();
        });
    }
}

class RotatePanel extends JPanel implements ActionListener {

    private static final int SIZE = 256;
    private static final 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(SIZE, SIZE));
        this.addMouseListener(new MouseAdapter() {

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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.rotate(theta,128,128);
        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);
        final Color c1 = Color.getHSBColor(r.nextFloat(), 1, 1);
        final Color c2 = Color.getHSBColor(r.nextFloat(), 1, 1);
        g2d.setPaint(c1);
        g2d.setStroke(new BasicStroke(10.0f));
        g2d.draw(new Line2D.Double(0, size/2, size, size/2));

        g2d.setPaint(c2);
        g2d.draw(new Line2D.Double(size/2, 0, size/2, size));

        g2d.setPaint(c1);
        g2d.draw(new Ellipse2D.Double(0, 0, size, size));
        g2d.dispose();
        return bi;
    }
}

说明:

  1. 因此,解决方案中的“摆动”来自于这样一个事实,即您将图像和容器/面板尺寸设置为256x256,但仅在200x200上“基于”您的车轮布局。我修正了所有尺寸,并绘制了一个正确的十字架,然后g2d.rotate(theta,128,128);(!)与中心相关。

  2. 多色(简单):您可以在每个形状之间调用setPaint()! ;)