Java 如何围绕JPanel中的一个点旋转一个圆?
我试图在程序中围绕一个单独的点旋转一个圆。现在我可以让圆旋转,但它慢慢地开始越来越接近它旋转的起点。我试图使用JPanel来实现这一点,并将其实现为一个矩形Java 如何围绕JPanel中的一个点旋转一个圆?,java,swing,jpanel,awt,Java,Swing,Jpanel,Awt,我试图在程序中围绕一个单独的点旋转一个圆。现在我可以让圆旋转,但它慢慢地开始越来越接近它旋转的起点。我试图使用JPanel来实现这一点,并将其实现为一个矩形 package WoffindenZone; import java.awt.*; import javax.swing.*; import java.util.*; import java.awt.event.*; import java.lang.Math; public class Protector extends Rectangl
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);
}
使用仿射变换的旋转实例。有关详细信息,请参阅 返回围绕定位点旋转坐标的变换。此操作相当于平移坐标,使定位点位于原点(S1),然后围绕新原点(S2)旋转坐标,最后平移,使中间原点恢复到原始定位点(S3)的坐标 如何围绕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);
}
}
我不知道如何制作动画GIF。想象一下,蓝色圆圈绕着绘图中心顺时针旋转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);
}
}
那么,让我们从头开始。基本上,我有一个圆在另一个圆的圆周上旋转。因此,我从纯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
实例,一个内圈和一个外圈。下面是类构造函数设置绘图区域、内圈和外圈的首选大小。我们从零度(向右)开始外圆
现在,我们可以开始编写GUI了。首先,我们通过调用SwingUtilities
invokeLater
方法来启动Java应用程序。此方法确保我们在上创建和执行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
大小。我让用户设置我的JFrame
的大小。JFrame
内容窗格的默认布局是BorderLayout
。我将我的绘图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);
}
}
绘图JPanel
所做的就是绘制一个圆
对象。很简单
fillOval
方法从左上角绘制一个椭圆形。我们从中心点计算左上角的点
计算和更新外圈中心点的责任落在我的控制器类上,动画类。我使用一个简单的循环来更新θ角,计算新的外圈中心点,绘制外圈,然后等待一段时间
这是密码
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
方法中调用绘图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;
}
}
}
Java命名约定使用大写字母作为类的名称;变量和方法以小写字母(方向)开头。常量使用所有的大写字母和蛇壳。@NomadMaker起初我有一个xDirection和yDirection,并使圆圈自由移动,所以当我更改内容时,我忘了将d更改为小写字母。感谢heads upStore为x
和y
存储double
值,并在每次计算新值时使用double
值。当您实际调用fillOval
时,仅将圆/强制转换为int
。创建一个包含中心java.awt.Point和int半径的圆类。创建要绘制的圆和围绕旋转圆旋转绘制圆的圆。在一幅画上画画。请参见Oracle教程以查看示例。