问题描述
我正在尝试绕程序中的单独点旋转一个圆。现在,我可以使圆旋转,但是它慢慢开始越来越接近旋转的起点。我正在尝试使用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,width,height);
}
解决方法
使用AffineTransform
的旋转实例。有关详细信息,请参见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,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 layout managers设置了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
方法在另一个JPanel
repaint
方法内调用图形SwingUtilities
invokeLater
方法。此方法可确保绘图发生在事件调度线程上。
最后,这是完整的,可运行的示例。我使用了内部类,因此我可以将代码作为一个块发布,并且可以将这些代码作为一个块复制并运行。通常,类应放在单独的文件中,而对于更复杂的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,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;
}
}
}