[英]How do you rotate a circle about a point in JPanel?
I am trying to rotate a circle around a separate point in a program.我试图在程序中围绕一个单独的点旋转一个圆圈。 right now I can get the circle to rotate but it slowly starts getting closer and closer to the point it's rotating from.
现在我可以让圆圈旋转,但它慢慢地开始越来越接近它旋转的起点。 I am trying to do this using JPanel and implementing it as a rectangle.
我正在尝试使用 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);
}
Use a rotation instance of an AffineTransform
.使用
AffineTransform
的旋转实例。 See getRotateInstance(theta,anchorx,anchory)
for details.有关详细信息
getRotateInstance(theta,anchorx,anchory)
请参阅getRotateInstance(theta,anchorx,anchory)
。
Returns a transform that rotates coordinates around an anchor point.
返回围绕锚点旋转坐标的变换。 This operation is equivalent to translating the coordinates so that the anchor point is at the origin (S1), then rotating them about the new origin (S2), and finally translating so that the intermediate origin is restored to the coordinates of the original anchor point (S3).
这个操作相当于平移坐标,使锚点在原点(S1),然后绕新原点(S2)旋转,最后平移,使中间原点恢复到原锚点的坐标(S3)。
How do you rotate a circle about a point in JPanel?
你如何在JPanel中围绕一个点旋转一个圆?
Here's how I rotate a circle about a point in a JPanel
.这是我如何围绕
JPanel
一个点旋转一个圆。
I don't know how to make an animated GIF.我不知道如何制作动画 GIF。 Just imagine the blue circle rotating clockwise around the center of the drawing
JPanel
.想象一下蓝色圆圈围绕绘图
JPanel
的中心顺时针旋转。
So, let's start at the beginning.所以,让我们从头开始。 Basically, I have a circle rotating on the circumference of another circle.
基本上,我有一个圆在另一个圆的圆周上旋转。 So, I create a
Circle
model class from plain Java.因此,我从纯 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;
}
}
The class consists of basic getters and setters.该类由基本的 getter 和 setter 组成。 I make the radius and color
final
because they don't change value in this Java application.我将半径和颜色
final
值,因为它们不会更改此 Java 应用程序中的值。
The calculateCircumferencePoint
method is the only interesting method. calculateCircumferencePoint
方法是唯一有趣的方法。 It takes an int
angle in degrees, and calculates the point on the circumference represented by that angle, rounded to the nearest X and Y integer points.它需要一个以度为单位的
int
角度,并计算该角度表示的圆周上的点,四舍五入到最近的 X 和 Y 整数点。
Next, we create two Circle
instances, an inner circle and an outer circle.接下来,我们创建两个
Circle
实例,一个内圆和一个外圆。 Here's the class constructor setting the preferred size of the drawing area, the inner circle, and the outer circle.这是设置绘图区域、内圆和外圆的首选大小的类构造函数。 We start the outer circle at zero degrees (to the right);
我们从零度(向右)开始外圆;
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);
}
Now, we can start coding the GUI.现在,我们可以开始编写 GUI。 First, we start the Java application by calling the
SwingUtilities
invokeLater
method.首先,我们通过调用
SwingUtilities
invokeLater
方法启动 Java 应用程序。 This method ensures that we create and execute the Swing components on the Event Dispatch Thread .此方法确保我们在Event Dispatch Thread上创建和执行 Swing 组件。
Next, we define the JFrame
.接下来,我们定义
JFrame
。 Here's the code we have so far.这是我们到目前为止的代码。
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();
}
The JFrame
methods must be called in a certain order. JFrame
方法必须按特定顺序调用。 This is the order I use for most of my SWwing applications.这是我用于大多数 SWwing 应用程序的顺序。
I pack the JFrame
.我打包
JFrame
。 I don't set a JFrame
size.我没有设置
JFrame
大小。 I let the Swing layout managers set the size of my JFrame
.我让Swing 布局管理器设置我的
JFrame
的大小。 The default layout of a JFrame
content pane is a BorderLayout
. JFrame
内容窗格的默认布局是BorderLayout
。 I put my drawing JPanel
in the center of the BorderLayout
.我将我的绘图
JPanel
放在BorderLayout
的中心。
Next, I create the drawing JPanel
.接下来,我创建绘图
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);
}
}
All the drawing JPanel
does is paint a Circle
object. JPanel
所做的所有绘图都是绘制一个Circle
对象。 Pretty straightforward.很简单。
The fillOval
method paints an oval from the upper left hand corner. fillOval
方法从左上角绘制一个椭圆。 We calculate the upper left hand point from the center point.我们从中心点计算左上角。
The responsibility for calculating and updating the outer circle center point falls to my controller class, the Animation
class.计算和更新外圆中心点的责任落在我的控制器类,
Animation
类。 I use a simple loop to update the theta angle, calculate the new outer circle center point, paint the outer circle, and wait a period of time.我用一个简单的循环更新theta角,计算新的外圆中心点,画外圆,等待一段时间。
Here's that code.这是那个代码。
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();
}
}
}
The Animation
repaint
method makes the call to the drawing JPanel
repaint
method inside another SwingUtilities
invokeLater
method. Animation
repaint
方法调用另一个SwingUtilities
invokeLater
方法中的绘图JPanel
repaint
方法。 This method ensures that the drawing happens on the Event Dispatch Thread.此方法确保绘制发生在事件调度线程上。
Finally, here's the complete, runnable, example.最后,这是完整的、可运行的示例。 I used inner classes so I could post the code as one block, and you can copy and run this code as one block.
我使用了内部类,因此我可以将代码作为一个块发布,您可以将这些代码作为一个块复制和运行。 Generally, classes should be in separate files and for a more complex GUI, separate packages.
通常,类应该在单独的文件中,对于更复杂的 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.