无法手动绘制到 JPanel
Unable to draw manually to JPanel
我正在尝试制作一个轨道模拟器,我 运行 遇到了这个问题。我已经检查了整个 Stack Overflow,但找不到解决方案。我只是想手动绘制到 JPanel
,但它没有显示出来。我已将布局设置为空,使其可见,将其添加到 JFrame
,将正文添加到 Plane
,以及您通常会做的所有事情。
这是正文class:
package viperlordx.orbitsimulator;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JLabel;
@SuppressWarnings("serial")
public class Body extends JLabel {
private double mass;
private Point location;
private Vector velocity;
private Color color;
private Plane plane;
public Body(double mass, Point location, Vector velocity, Color color) {
this.mass = mass;
this.location = location;
this.velocity = velocity;
this.color = color;
this.setVisible(true);
this.setBounds(location.x, location.y, 100, 100);
}
public void moveTick() {
velocity.addTo(location);
}
public void setPlane(Plane plane) {
this.plane = plane;
}
public Plane getPlane() {
return plane;
}
@Override
public void paintComponent(Graphics g) {
System.out.println("Painting");
super.paintComponent(g);
if (plane != null && g != null) {
g.setColor(color);
g.fillOval(location.x, location.y, getWidth(), getHeight());
}
}
public Point getLocation() {
return location;
}
public void setLocation(Point location) {
this.location = location;
}
public Vector getVelocity() {
return velocity;
}
public void setVelocity(Vector vector) {
velocity = vector;
}
}
飞机class:
package viperlordx.orbitsimulator;
import java.awt.Graphics;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Plane extends JPanel {
private HashSet<Body> bodies = new HashSet<Body>();
public void addBody(Body body) {
this.add(body);
bodies.add(body);
}
public Plane() {
this.setLayout(null);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bodies != null) {
for (Body body : bodies) {
body.paintComponent(g);
}
}
}
public Set<Body> getBodies() {
return bodies;
}
}
现在主要class:
package viperlordx.orbitsimulator;
import java.awt.Color;
import java.awt.Point;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 1000);
frame.setLocationRelativeTo(null);
Plane plane = new Plane();
frame.add(plane);
plane.setVisible(true);
frame.setLayout(null);
plane.setBounds(0, 0, 1000, 1000);
plane.setBackground(Color.WHITE);
plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));
frame.setVisible(true);
frame.setTitle("Orbit");
plane.repaint();
}
}
您混淆了组件上的绘图形状和将组件添加到容器中。你的 Body
不应该是一个组件,只是一个 class 保存要绘制的对象的数据。此数据用于在 "target" 组件 上绘制一个 对应的形状 - 在您的案例中是 Plane
。
我删除了不相关的代码并根据我上面的解释进行了更改:
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
Plane plane = new Plane();
frame.add(plane);
plane.setBackground(Color.WHITE);
plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Orbit");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
@SuppressWarnings("serial")
class Plane extends JPanel {
private HashSet<Body> bodies = new HashSet<>();
public void addBody(Body body) {
bodies.add(body);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Body body : bodies) {
// Might want to call all needed accessors before getting to work.
g.setColor(body.getColor());
g.fillOval(body.getLocation().x, body.getLocation().y, getWidth(), getHeight());
}
}
@Override
public Dimension getPreferredSize() {
// Calculate the size
return new Dimension(1000, 500);
}
}
class Body {
private Point location;
private Vector velocity;
private Color color;
public Body(double mass, Point location, Vector velocity, Color color) {
this.location = location;
this.velocity = velocity;
this.color = color;
}
public Point getLocation() {
return location;
}
public Color getColor() {
return color;
}
}
备注:
- Start Swing on the EDT.
- 不要设置框架的大小(如果我的屏幕没有 1000 像素的高度怎么办?),改为调用 pack() 并确保组件您在其上适当绘制
@Override getPreferredSize()
。这意味着您将需要根据您在其上绘制的内容进行计算。
- 一般来说,
setVisible(true)
应该是你做的最后一件事。完成后无需重绘。
- 自 Java7 起,您可以编写
HashSet<Body> bodies = new HashSet<>()
而无需在 RHS 中指定泛型类型。
- 不要使用原始类型
Vector
。事实上,根本没有理由使用这个 class。 Set
或 List
通常会做得更好。如果他们持有计算中使用的数字,那么他们的通用类型应该是 Float
或 Double
可能。
我正在尝试制作一个轨道模拟器,我 运行 遇到了这个问题。我已经检查了整个 Stack Overflow,但找不到解决方案。我只是想手动绘制到 JPanel
,但它没有显示出来。我已将布局设置为空,使其可见,将其添加到 JFrame
,将正文添加到 Plane
,以及您通常会做的所有事情。
这是正文class:
package viperlordx.orbitsimulator;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JLabel;
@SuppressWarnings("serial")
public class Body extends JLabel {
private double mass;
private Point location;
private Vector velocity;
private Color color;
private Plane plane;
public Body(double mass, Point location, Vector velocity, Color color) {
this.mass = mass;
this.location = location;
this.velocity = velocity;
this.color = color;
this.setVisible(true);
this.setBounds(location.x, location.y, 100, 100);
}
public void moveTick() {
velocity.addTo(location);
}
public void setPlane(Plane plane) {
this.plane = plane;
}
public Plane getPlane() {
return plane;
}
@Override
public void paintComponent(Graphics g) {
System.out.println("Painting");
super.paintComponent(g);
if (plane != null && g != null) {
g.setColor(color);
g.fillOval(location.x, location.y, getWidth(), getHeight());
}
}
public Point getLocation() {
return location;
}
public void setLocation(Point location) {
this.location = location;
}
public Vector getVelocity() {
return velocity;
}
public void setVelocity(Vector vector) {
velocity = vector;
}
}
飞机class:
package viperlordx.orbitsimulator;
import java.awt.Graphics;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Plane extends JPanel {
private HashSet<Body> bodies = new HashSet<Body>();
public void addBody(Body body) {
this.add(body);
bodies.add(body);
}
public Plane() {
this.setLayout(null);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bodies != null) {
for (Body body : bodies) {
body.paintComponent(g);
}
}
}
public Set<Body> getBodies() {
return bodies;
}
}
现在主要class:
package viperlordx.orbitsimulator;
import java.awt.Color;
import java.awt.Point;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 1000);
frame.setLocationRelativeTo(null);
Plane plane = new Plane();
frame.add(plane);
plane.setVisible(true);
frame.setLayout(null);
plane.setBounds(0, 0, 1000, 1000);
plane.setBackground(Color.WHITE);
plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));
frame.setVisible(true);
frame.setTitle("Orbit");
plane.repaint();
}
}
您混淆了组件上的绘图形状和将组件添加到容器中。你的 Body
不应该是一个组件,只是一个 class 保存要绘制的对象的数据。此数据用于在 "target" 组件 上绘制一个 对应的形状 - 在您的案例中是 Plane
。
我删除了不相关的代码并根据我上面的解释进行了更改:
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
Plane plane = new Plane();
frame.add(plane);
plane.setBackground(Color.WHITE);
plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Orbit");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
@SuppressWarnings("serial")
class Plane extends JPanel {
private HashSet<Body> bodies = new HashSet<>();
public void addBody(Body body) {
bodies.add(body);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Body body : bodies) {
// Might want to call all needed accessors before getting to work.
g.setColor(body.getColor());
g.fillOval(body.getLocation().x, body.getLocation().y, getWidth(), getHeight());
}
}
@Override
public Dimension getPreferredSize() {
// Calculate the size
return new Dimension(1000, 500);
}
}
class Body {
private Point location;
private Vector velocity;
private Color color;
public Body(double mass, Point location, Vector velocity, Color color) {
this.location = location;
this.velocity = velocity;
this.color = color;
}
public Point getLocation() {
return location;
}
public Color getColor() {
return color;
}
}
备注:
- Start Swing on the EDT.
- 不要设置框架的大小(如果我的屏幕没有 1000 像素的高度怎么办?),改为调用 pack() 并确保组件您在其上适当绘制
@Override getPreferredSize()
。这意味着您将需要根据您在其上绘制的内容进行计算。 - 一般来说,
setVisible(true)
应该是你做的最后一件事。完成后无需重绘。 - 自 Java7 起,您可以编写
HashSet<Body> bodies = new HashSet<>()
而无需在 RHS 中指定泛型类型。 - 不要使用原始类型
Vector
。事实上,根本没有理由使用这个 class。Set
或List
通常会做得更好。如果他们持有计算中使用的数字,那么他们的通用类型应该是Float
或Double
可能。