Java awt 围绕一个圆圈绘制元素
Java awt draw elements around a circle
我正在写一个小游戏,遇到了一个问题。我需要在一个大圆的边界处画 64 个小圆。所以我想要这样的东西:
我已经尝试了很多东西,但都没有用。如何在 java 中使用 java.awt.Component#paint() 方法和 java.awt.Graphics class?
完成此操作
谢谢。
因此,您的基本问题归结为“根据给定角度在圆上找到一个点”
快速 google 会找到像 Find the coordinates of a point on a circle, now, to be frank, I'm an idiot, so I'd narrow my search to include Java, which would give us something like - sweet.
这样的资源
所以基本计算可能类似于
double xPosy = Math.cos(rads) * radius);
double yPosy = Math.sin(rads) * radius);
现在,这解决了您问题的核心方面。剩下的就是简单地绘制结果。有关 API.
的更详细信息,请参阅 Performing Custom Painting and Painting in AWT and Swing as a starting point and 2D Graphics
现在,考虑到以上所有内容,您最终可能会得到一个类似于...
的解决方案
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int midX = getWidth() / 2;
int midY = getHeight() / 2;
Dimension size = new Dimension(4, 4);
g2d.setColor(Color.BLACK);
for (int index = 0; index < 64; index++) {
double angle = (360d / 64d) * index;
Point2D poc = getPointOnCircle(angle, 100 - 4);
Rectangle2D box = new Rectangle2D.Double(midX + poc.getX() - 2, midY + poc.getY() - 2, size.width, size.height);
g2d.draw(box);
}
g2d.dispose();
}
protected Point2D getPointOnCircle(double degress, double radius) {
double rads = Math.toRadians(degress - 90); // 0 becomes the top
return new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
}
}
}
所以,大约现在,您应该意识到我的“正方形”是正方形,而不是像您的“菱形”形状。这是您必须开始做一些工作的地方。
如果我正在处理这个问题,我可能会想创建一个自定义形状,或者对 box
应用 45 度变换并平移它的位置以渲染它,或者只是将整个结果旋转45 度,但这会带来一大堆其他问题,具体取决于您要用它做什么
这是一种方法(其中大部分是用于设置包含框架和面板的样板)。它使用 sine and cosine
方法计算 unit
圆的点。然后通过首先乘以所需较大圆的 radius
然后通过添加 center x,y
偏移量将其置于面板中心来调整这些点。
它包含的唯一真正特别的东西是
- 保证外圆之间的距离为其直径之一。因此,如果圆圈数量减少,则尺寸会增加。这可以根据您的需要进行调整。
- 我使用
RenderingHints
在视觉上平滑了曲线。最后
- 我添加了一个具有任意限制的简单
WheelListener
,这样您可以在上下移动鼠标滚轮时看到变化。这会修改 NCIRCLES
(不应该用常量做的事情)然后重新绘制面板。它很容易删除。
public class CircleBorder extends JPanel {
JFrame frame = new JFrame("Circle Border");
static int BIG_RADIUS = 200;
static int NCIRCLES = 60;
static int WIDTH = 500;
static int HEIGHT = 500;
public static void main(String[] args ) {
SwingUtilities.invokeLater(()->new CircleBorder().start());
}
public void start() {
addMouseWheelListener((we)-> {
int rot = we.getWheelRotation();
if (NCIRCLES < 70 && rot > 0 || NCIRCLES > 7 && rot < 0) {
NCIRCLES += rot;
}
repaint();
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
// center on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH,HEIGHT);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int centerX = WIDTH/2;
int centerY = HEIGHT/2;
double angleIncrement = 2*Math.PI/NCIRCLES;
g2d.setColor(Color.RED);
// the next two lines adjusts the little radius so that each
// outer circle will be one diameter apart.
int bigD = (int)(Math.PI*2*BIG_RADIUS);
int littleRadius = bigD/(NCIRCLES*4);
// Compute the x and y coordinates of the center of the outer
// circles. Then iterate once around the circle based on the
// computed angle above to draw the circumference. The little
// radius is subtracted to ensure those circles are
// centered on the large circles circumference.
double angle = 0;
for (int i = 0; i < NCIRCLES; i++) {
int x = (int)(centerX + Math.cos(angle)*BIG_RADIUS)
- littleRadius;
int y = (int)(centerY + Math.sin(angle)*BIG_RADIUS)
- littleRadius;
g2d.fillOval(x,y,littleRadius*2,littleRadius*2);
angle += angleIncrement;
}
g2d.dispose();
}
}
感谢@MadProgrammer 的回答。我将他的代码与@WJS 提出的使用 RenderingHints 的建议和我自己的想法结合起来,下面的代码对我有用。
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
/**
* Thanks to <a
* href=https://whosebug.com/users/992484/madprogrammer>@MadProgrammer</a>
* on Whosebug for the geometry part (<a
* href=
* code</a>)
*/
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JComponent {
public TestPane() {
}
@Override
public Dimension getPreferredSize() {
return getParent().getSize();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
//Thanks to @WJS for the idea
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int midX = getWidth() / 2;
int midY = getHeight() / 2;
int min = Math.min(getHeight() / 2, getWidth() / 2);
Dimension size = new Dimension(min / 20, min / 20);
double minsize = Math.min(size.getHeight(), size.getWidth());
double radius = min - minsize;
g2d.setColor(Color.BLACK);
for (int index = 0; index < 64; index++) {
double angle = (360d / 64d) * index;
double rads = Math.toRadians(angle - 90); // 0 becomes the top
Point2D poc = new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
g2d.fillOval((int) (midX + poc.getX() - 2), (int) (midY + poc.getY() - 2), size.width, size.height);
}
g2d.dispose();
}
}
}
我正在写一个小游戏,遇到了一个问题。我需要在一个大圆的边界处画 64 个小圆。所以我想要这样的东西:
我已经尝试了很多东西,但都没有用。如何在 java 中使用 java.awt.Component#paint() 方法和 java.awt.Graphics class?
完成此操作谢谢。
因此,您的基本问题归结为“根据给定角度在圆上找到一个点”
快速 google 会找到像 Find the coordinates of a point on a circle, now, to be frank, I'm an idiot, so I'd narrow my search to include Java, which would give us something like
所以基本计算可能类似于
double xPosy = Math.cos(rads) * radius);
double yPosy = Math.sin(rads) * radius);
现在,这解决了您问题的核心方面。剩下的就是简单地绘制结果。有关 API.
的更详细信息,请参阅 Performing Custom Painting and Painting in AWT and Swing as a starting point and 2D Graphics现在,考虑到以上所有内容,您最终可能会得到一个类似于...
的解决方案import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int midX = getWidth() / 2;
int midY = getHeight() / 2;
Dimension size = new Dimension(4, 4);
g2d.setColor(Color.BLACK);
for (int index = 0; index < 64; index++) {
double angle = (360d / 64d) * index;
Point2D poc = getPointOnCircle(angle, 100 - 4);
Rectangle2D box = new Rectangle2D.Double(midX + poc.getX() - 2, midY + poc.getY() - 2, size.width, size.height);
g2d.draw(box);
}
g2d.dispose();
}
protected Point2D getPointOnCircle(double degress, double radius) {
double rads = Math.toRadians(degress - 90); // 0 becomes the top
return new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
}
}
}
所以,大约现在,您应该意识到我的“正方形”是正方形,而不是像您的“菱形”形状。这是您必须开始做一些工作的地方。
如果我正在处理这个问题,我可能会想创建一个自定义形状,或者对 box
应用 45 度变换并平移它的位置以渲染它,或者只是将整个结果旋转45 度,但这会带来一大堆其他问题,具体取决于您要用它做什么
这是一种方法(其中大部分是用于设置包含框架和面板的样板)。它使用 sine and cosine
方法计算 unit
圆的点。然后通过首先乘以所需较大圆的 radius
然后通过添加 center x,y
偏移量将其置于面板中心来调整这些点。
它包含的唯一真正特别的东西是
- 保证外圆之间的距离为其直径之一。因此,如果圆圈数量减少,则尺寸会增加。这可以根据您的需要进行调整。
- 我使用
RenderingHints
在视觉上平滑了曲线。最后 - 我添加了一个具有任意限制的简单
WheelListener
,这样您可以在上下移动鼠标滚轮时看到变化。这会修改NCIRCLES
(不应该用常量做的事情)然后重新绘制面板。它很容易删除。
public class CircleBorder extends JPanel {
JFrame frame = new JFrame("Circle Border");
static int BIG_RADIUS = 200;
static int NCIRCLES = 60;
static int WIDTH = 500;
static int HEIGHT = 500;
public static void main(String[] args ) {
SwingUtilities.invokeLater(()->new CircleBorder().start());
}
public void start() {
addMouseWheelListener((we)-> {
int rot = we.getWheelRotation();
if (NCIRCLES < 70 && rot > 0 || NCIRCLES > 7 && rot < 0) {
NCIRCLES += rot;
}
repaint();
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
// center on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH,HEIGHT);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int centerX = WIDTH/2;
int centerY = HEIGHT/2;
double angleIncrement = 2*Math.PI/NCIRCLES;
g2d.setColor(Color.RED);
// the next two lines adjusts the little radius so that each
// outer circle will be one diameter apart.
int bigD = (int)(Math.PI*2*BIG_RADIUS);
int littleRadius = bigD/(NCIRCLES*4);
// Compute the x and y coordinates of the center of the outer
// circles. Then iterate once around the circle based on the
// computed angle above to draw the circumference. The little
// radius is subtracted to ensure those circles are
// centered on the large circles circumference.
double angle = 0;
for (int i = 0; i < NCIRCLES; i++) {
int x = (int)(centerX + Math.cos(angle)*BIG_RADIUS)
- littleRadius;
int y = (int)(centerY + Math.sin(angle)*BIG_RADIUS)
- littleRadius;
g2d.fillOval(x,y,littleRadius*2,littleRadius*2);
angle += angleIncrement;
}
g2d.dispose();
}
}
感谢@MadProgrammer 的回答。我将他的代码与@WJS 提出的使用 RenderingHints 的建议和我自己的想法结合起来,下面的代码对我有用。
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
/**
* Thanks to <a
* href=https://whosebug.com/users/992484/madprogrammer>@MadProgrammer</a>
* on Whosebug for the geometry part (<a
* href=
* code</a>)
*/
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JComponent {
public TestPane() {
}
@Override
public Dimension getPreferredSize() {
return getParent().getSize();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
//Thanks to @WJS for the idea
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int midX = getWidth() / 2;
int midY = getHeight() / 2;
int min = Math.min(getHeight() / 2, getWidth() / 2);
Dimension size = new Dimension(min / 20, min / 20);
double minsize = Math.min(size.getHeight(), size.getWidth());
double radius = min - minsize;
g2d.setColor(Color.BLACK);
for (int index = 0; index < 64; index++) {
double angle = (360d / 64d) * index;
double rads = Math.toRadians(angle - 90); // 0 becomes the top
Point2D poc = new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
g2d.fillOval((int) (midX + poc.getX() - 2), (int) (midY + poc.getY() - 2), size.width, size.height);
}
g2d.dispose();
}
}
}