簡體   English   中英

使用 Swing 和 Graphics2D 在 Java 中旋轉輪子?

[英]Rotating a wheel in Java using Swing and Graphics2D?

我正在研究一個可以圍繞中心旋轉輪子的課程。 輪子是使用 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;
}
}

您可以使用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 RotatedIcon rotated;
    private int degrees;

    public Rotation4(Image image)
    {
        setLayout( new GridBagLayout() );

        Icon icon = new ImageIcon( image );
        rotated = new RotatedIcon(icon, 0);
        rotated.setCircularIcon(true);
        label = new JLabel(rotated);
        label.setOpaque(true);
        label.setBackground(Color.RED);
        add(label, new GridBagConstraints());
        setDegrees( 0 );
    }

    public void setDegrees(int degrees)
    {
        this.degrees = degrees;
        rotated.setDegrees( degrees );
        label.revalidate();
        label.repaint();
    }

    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.setSize(400, 400);
                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(105, 5, 105, 205));
            g2d.draw(new Line2D.Double(35, 35, 175, 175));
            g2d.draw(new Line2D.Double(175, 35, 35, 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。)要在(原始)代碼中進行中心旋轉,只需將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() ;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM