簡體   English   中英

你如何在JPanel中圍繞一個點旋轉一個圓?

[英]How do you rotate a circle about a point in JPanel?

我試圖在程序中圍繞一個單獨的點旋轉一個圓圈。 現在我可以讓圓圈旋轉,但它慢慢地開始越來越接近它旋轉的起點。 我正在嘗試使用 JPanel 並將其實現為矩形。

package WoffindenZone;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import java.lang.Math;
public class Protector extends Rectangle{
double Velocity;
int speed = 3;
Protector(int x, int y, int PROTECTOR_DIAMETER){
    super(x,y,PROTECTOR_DIAMETER,PROTECTOR_DIAMETER);
}

public void keyPressed(KeyEvent e){
    if(e.getKeyCode()==KeyEvent.VK_A) {
        setDirection(speed);
        move();
    }
    if(e.getKeyCode()==KeyEvent.VK_D) {
        setDirection(speed);
        move();
    }
}
public void keyReleased(KeyEvent e){
    if(e.getKeyCode()==KeyEvent.VK_A) {
        setDirection(0);
        move();
    }
    if(e.getKeyCode()==KeyEvent.VK_D) {
        setDirection(0);
        move();
    }
}
public void setDirection(int Direction){
    Velocity = Direction*Math.PI/180;
}

public void move(){
    x = (int)Math.round(500 + Math.cos(Velocity) * (x-500) - Math.sin(Velocity) * (y-((1000*0.5555)/2)));
    y = (int)Math.round(((1000*0.5555)/2) + Math.sin(Velocity) * (x-500) + Math.cos(Velocity) * (y-((1000*0.5555)/2)));
    System.out.println(x);
    System.out.println(y);
}
public void draw(Graphics g){
    g.setColor(Color.blue);
    g.fillOval(x,y,width,height);
}    

使用AffineTransform的旋轉實例。 有關詳細信息getRotateInstance(theta,anchorx,anchory)請參閱getRotateInstance(theta,anchorx,anchory)

返回圍繞錨點旋轉坐標的變換。 這個操作相當於平移坐標,使錨點在原點(S1),然后繞新原點(S2)旋轉,最后平移,使中間原點恢復到原錨點的坐標(S3)。

你如何在JPanel中圍繞一個點旋轉一個圓?

這是我如何圍繞JPanel一個點旋轉一個圓。

旋轉圓圖形用戶界面

我不知道如何制作動畫 GIF。 想象一下藍色圓圈圍繞繪圖JPanel的中心順時針旋轉。

所以,讓我們從頭開始。 基本上,我有一個圓在另一個圓的圓周上旋轉。 因此,我從純 Java 創建了一個Circle模型類。

public class Circle {
    
    private final int radius;
    
    private final Color color;
    
    private Point center;
    
    public Circle(int radius, Color color) {
        this.radius = radius;
        this.color = color;
    }
    
    public Point calculateCircumferencePoint(int theta) {
        double radians = Math.toRadians(theta);
        int x = center.x + (int) Math.round(Math.cos(radians) * radius);
        int y = center.y + (int) Math.round(Math.sin(radians) * radius);
        return new Point(x, y);
    }
    
    public void setCenter(int x, int y) {
        this.center = new Point(x, y);
    }

    public void setCenter(Point center) {
        this.center = center;
    }

    public int getRadius() {
        return radius;
    }

    public Color getColor() {
        return color;
    }

    public Point getCenter() {
        return center;
    }
    
}

該類由基本的 getter 和 setter 組成。 我將半徑和顏色final值,因為它們不會更改此 Java 應用程序中的值。

calculateCircumferencePoint方法是唯一有趣的方法。 它需要一個以度為單位的int角度,並計算該角度表示的圓周上的點,四舍五入到最近的 X 和 Y 整數點。

接下來,我們創建兩個Circle實例,一個內圓和一個外圓。 這是設置繪圖區域、內圓和外圓的首選大小的類構造函數。 我們從零度(向右)開始外圓;

private Circle innerCircle;
private Circle outerCircle;

private Dimension drawingPanelSize;

public RotateCircle() {
    this.drawingPanelSize = new Dimension(400, 400);
    int innerCircleRadius = drawingPanelSize.width / 4;
    int centerX = drawingPanelSize.width / 2;
    int centerY = drawingPanelSize.height / 2;
    int outerCircleRadius = drawingPanelSize.width / 10;
    
    this.innerCircle = new Circle(innerCircleRadius, null);
    this.innerCircle.setCenter(centerX, centerY);
    this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
    Point point = innerCircle.calculateCircumferencePoint(0);
    this.outerCircle.setCenter(point);
}

現在,我們可以開始編寫 GUI。 首先,我們通過調用SwingUtilities invokeLater方法啟動 Java 應用程序。 此方法確保我們在Event Dispatch Thread上創建和執行 Swing 組件。

接下來,我們定義JFrame 這是我們到目前為止的代碼。

public static void main(String[] args) {
    SwingUtilities.invokeLater(new RotateCircle());
}

private Animation animation;

private Circle innerCircle;
private Circle outerCircle;

private DrawingPanel drawingPanel;

private Dimension drawingPanelSize;

public RotateCircle() {
    this.drawingPanelSize = new Dimension(400, 400);
    int innerCircleRadius = drawingPanelSize.width / 4;
    int centerX = drawingPanelSize.width / 2;
    int centerY = drawingPanelSize.height / 2;
    int outerCircleRadius = drawingPanelSize.width / 10;
    
    this.innerCircle = new Circle(innerCircleRadius, null);
    this.innerCircle.setCenter(centerX, centerY);
    this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
    Point point = innerCircle.calculateCircumferencePoint(0);
    this.outerCircle.setCenter(point);
}

@Override
public void run() {
    JFrame frame = new JFrame("Rotate Circle");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    drawingPanel = new DrawingPanel(drawingPanelSize, 
            outerCircle);
    frame.add(drawingPanel, BorderLayout.CENTER);
    
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);
    
    animation = new Animation(0);
    new Thread(animation).start();
}

JFrame方法必須按特定順序調用。 這是我用於大多數 SWwing 應用程序的順序。

我打包JFrame 我沒有設置JFrame大小。 我讓Swing 布局管理器設置我的JFrame的大小。 JFrame內容窗格的默認布局是BorderLayout 我將我的繪圖JPanel放在BorderLayout的中心。

接下來,我創建繪圖JPanel

public class DrawingPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    
    private Circle circle;
    
    public DrawingPanel(Dimension size, Circle circle) {
        this.circle = circle;
        this.setBackground(Color.WHITE);
        this.setPreferredSize(size);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        
        Point center = circle.getCenter();
        int radius = circle.getRadius();
        int diameter = radius + radius;
        g2d.setColor(circle.getColor());
        g2d.fillOval(center.x - radius, center.y - radius, 
                diameter, diameter);
    }
    
}

JPanel所做的所有繪圖都是繪制一個Circle對象。 很簡單。

fillOval方法從左上角繪制一個橢圓。 我們從中心點計算左上角。

計算和更新外圓中心點的責任落在我的控制器類, Animation類。 我用一個簡單的循環更新theta角,計算新的外圓中心點,畫外圓,等待一段時間。

這是那個代碼。

public class Animation implements Runnable {
    
    private int theta;
    
    public Animation(int theta) {
        this.theta = theta;
    }
    
    @Override
    public void run() {
        while (true) {
            theta++;
            theta = (theta >= 360) ? 0 : theta;
            
            Point center = innerCircle.calculateCircumferencePoint(theta);
            outerCircle.setCenter(center);
            repaint();
            sleep(30L);
        }
    }
    
    private void repaint() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                drawingPanel.repaint();
            }
        });
    }
    
    private void sleep(long duration) {
        try {
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
}

Animation repaint方法調用另一個SwingUtilities invokeLater方法中的繪圖JPanel repaint方法。 此方法確保繪制發生在事件調度線程上。

最后,這是完整的、可運行的示例。 我使用了內部類,因此我可以將代碼作為一個塊發布,您可以將這些代碼作為一個塊復制和運行。 通常,類應該在單獨的文件中,對於更復雜的 GUI,應該在單獨的包中。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class RotateCircle implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new RotateCircle());
    }
    
    private Animation animation;
    
    private Circle innerCircle;
    private Circle outerCircle;
    
    private DrawingPanel drawingPanel;
    
    private Dimension drawingPanelSize;
    
    public RotateCircle() {
        this.drawingPanelSize = new Dimension(400, 400);
        int innerCircleRadius = drawingPanelSize.width / 4;
        int centerX = drawingPanelSize.width / 2;
        int centerY = drawingPanelSize.height / 2;
        int outerCircleRadius = drawingPanelSize.width / 10;
        
        this.innerCircle = new Circle(innerCircleRadius, null);
        this.innerCircle.setCenter(centerX, centerY);
        this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
        Point point = innerCircle.calculateCircumferencePoint(0);
        this.outerCircle.setCenter(point);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Rotate Circle");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        drawingPanel = new DrawingPanel(drawingPanelSize, 
                outerCircle);
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        animation = new Animation(0);
        new Thread(animation).start();
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private Circle circle;
        
        public DrawingPanel(Dimension size, Circle circle) {
            this.circle = circle;
            this.setBackground(Color.WHITE);
            this.setPreferredSize(size);
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
            
            Point center = circle.getCenter();
            int radius = circle.getRadius();
            int diameter = radius + radius;
            g2d.setColor(circle.getColor());
            g2d.fillOval(center.x - radius, center.y - radius, 
                    diameter, diameter);
        }
        
    }
    
    public class Animation implements Runnable {
        
        private int theta;
        
        public Animation(int theta) {
            this.theta = theta;
        }
        
        @Override
        public void run() {
            while (true) {
                theta++;
                theta = (theta >= 360) ? 0 : theta;
                
                Point center = innerCircle.calculateCircumferencePoint(theta);
                outerCircle.setCenter(center);
                repaint();
                sleep(30L);
            }
        }
        
        private void repaint() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    drawingPanel.repaint();
                }
            });
        }
        
        private void sleep(long duration) {
            try {
                Thread.sleep(duration);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
    
    public class Circle {
        
        private final int radius;
        
        private final Color color;
        
        private Point center;
        
        public Circle(int radius, Color color) {
            this.radius = radius;
            this.color = color;
        }
        
        public Point calculateCircumferencePoint(int theta) {
            double radians = Math.toRadians(theta);
            int x = center.x + (int) Math.round(Math.cos(radians) * radius);
            int y = center.y + (int) Math.round(Math.sin(radians) * radius);
            return new Point(x, y);
        }
        
        public void setCenter(int x, int y) {
            this.center = new Point(x, y);
        }

        public void setCenter(Point center) {
            this.center = center;
        }

        public int getRadius() {
            return radius;
        }

        public Color getColor() {
            return color;
        }

        public Point getCenter() {
            return center;
        }
        
    }

}

暫無
暫無

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

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