[英]Draw on JPanel from another class at runtime
I have a class Roundabout(JFrame), Surface(JPanel) and Spawn. 我有一个类Roundabout(JFrame),Surface(JPanel)和Spawn。 In the Surface
paintComponent
I already draw some trafficlights, because they are always on the roundabout. 在Surface
paintComponent
我已经绘制了一些交通信号灯,因为它们始终在回旋处。 But I also want to draw components at runtime. 但是我也想在运行时绘制组件。 So I added a mousePressed event to the JFrame, the method I call here evetually calls
spawnPedestrian
from Spawn.java, I can see this because of the println
. 所以我添加到mousePressed事件到JFrame,我evetually调用这里的方法调用
spawnPedestrian
从Spawn.java,我可以看到,因为这样println
。 But when spawnPedestrian
is called nothing is painted! 但是当
spawnPedestrian
时, spawnPedestrian
都没有画! If I create a pedestrian in the Surface class and paint it, it works. 如果我在Surface类中创建了一个行人并对其进行绘制,那么它将起作用。 How I can make
spawnPedestrian
work?. 我如何使
spawnPedestrian
工作? I have tried to include the minimal code snippet (see below). 我试图包括最小的代码片段(见下文)。
human.png
human.png
roundabout.png
roundabout.png
public class Spawn {
public void spawnPedestrian(){
//Create a new pedestrian.
Pedestrian p = new Pedestrian(100,100);
Roundabout.getSurface().add(p);
Roundabout.getSurface().revalidate();
Roundabout.getSurface().repaint();
}
}
public class Roundabout extends JFrame{
static Surface surface=new Surface();
public Roundabout(){
initUI();
}
private void initUI() {
setTitle("Roundabout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(surface);
this.addMouseListener(new MouseAdapter() {// empty implementation of all
// MouseListener`s methods
@Override
public void mousePressed(MouseEvent e) {
System.out.println(e.getX() + "," + e.getY());
Spawn spawn=new Spawn();
spawn.spawnPedestrian();
}
});
setSize(1618,850);
setLocationRelativeTo(null);
}
public static JPanel getSurface() {
return surface;
}
public static void main(String[] args) {
//Swing thread
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Roundabout roundabout=new Roundabout();
roundabout.setVisible(true);
}
});
}
class Surface extends JPanel {
Track track=new Track();
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Make sure the track is painted first
track.paint(g);
}
}
public class Track{
BufferedImage track;
Point trackPosition;
static final Point TRACK_POS = new Point(0, 0);
static final Point SENSOR_POS = new Point(250, 70);
public Track(){
try {
track = ImageIO.read(Roundabout.class.getResource("images/roundabout.png"));
} catch (Exception ex) {
System.out.println("Problem loading track image: " + ex);
}
trackPosition=new Point(TRACK_POS.x,TRACK_POS.y);
}
public void paint(Graphics g)
{
g.drawImage(track,TRACK_POS.x, TRACK_POS.y, null);
}
}
public class Spawn {
//Needs x/y pos
public void spawnPedestrian(){
Pedestrian p = new Pedestrian(30,50);
System.out.println("Spawn me ");
Roundabout.getSurface().add(p);
Roundabout.getSurface().revalidate();
Roundabout.getSurface().repaint();
}
}
}
public class Pedestrian extends JComponent {
BufferedImage pedestrian;
Point pedestrianPosition;
double pedestrianRotation = 0;
int pedestrianW, pedestrianH;
public Pedestrian(int x, int y){
try {
pedestrian = ImageIO.read(Car.class.getResource("images/human.png"));
} catch (IOException e) {
System.out.println("Problem loading pedestrian images: " + e);
}
pedestrianPosition = new Point(x,y);
pedestrianW = pedestrian.getWidth();
pedestrianH = pedestrian.getHeight();
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.rotate(Math.toRadians(pedestrianRotation), pedestrianPosition.x, pedestrianPosition.y);
g2d.drawImage(pedestrian, pedestrianPosition.x, pedestrianPosition.y, null);
}
EDIT : Thought I solved it by setting the Surface
layout to null
and and by using setBounds
for Pedestrian
. 编辑:以为我通过将
Surface
布局设置为null
并通过对Pedestrian
使用setBounds
解决了它。 But the more I move the image to the right, the higher I have to set height
and width
in setBounds()
. 但是我将图像向右移动的次数越多,则必须在
setBounds()
设置height
和width
就越高。 Anyone who can help? 谁能帮忙?
EDIT: Modified my post, it is a runnable example now, you only have to pick your own images for Track
and Pedestrian
. 编辑:修改了我的帖子,现在它是一个可运行的示例,您只需要为
Track
和Pedestrian
选择自己的图像即可。
EDIT: One copy paste action to get the code and images added. 编辑:一个复制粘贴操作以获取添加的代码和图像。
When you write Roundabout.getSurface().add(p);
当您编写
Roundabout.getSurface().add(p);
, you are adding a JComponent to a JPanel
object. ,您正在将JComponent添加到
JPanel
对象。 JPanels must have a layout to display subcomponents. JPanels必须具有显示子组件的布局。 By default, this is the
FlowLayout
(see doc ). 默认情况下,这是
FlowLayout
(请参阅doc )。 FlowLayout is meant to display components next to the others in a row. FlowLayout用于将组件连续显示在其他组件旁边。 It won't support displaying components at arbitrary coordinates.
它不支持在任意坐标处显示组件。
I am not sure why the pedestrians are not displayed, but the reason could be that they have a dimension of 0x0. 我不确定为什么不显示行人,但是原因可能是行人的尺寸为0x0。 You can check that easily by using:
您可以使用以下方法轻松检查:
p.setPreferredSize(new Dimension(50,50));
Depending on your needs, you could follow a different approach: Instead of extending JPanel, Surface could be a simple Canvas, holding a list of "Paintables", such as the Pedestrians. 根据您的需求,您可以采用不同的方法:代替扩展JPanel,Surface可以是一个简单的Canvas,其中包含“ Paintables”列表,例如行人。 In
Surface.paintComponent()
, you can call each Paintable.paint()
, providing them the Graphics object: 在
Surface.paintComponent()
,可以调用每个Paintable.paint()
,为它们提供Graphics对象:
interface Paintable {
public void paint(Graphics2D g);
}
class Pedestrian implements Paintable {
public double x, y;
public void paint(Graphics2D g){
Shape circle = new Ellipse2D.Double(x - 5, y - 5, 10, 10);
g2d.draw(circle);
}
}
class Surface extends Canvas {
public List<Paintable> components = new ArrayList<Paintable>();
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(Paintable p : components)
p.paint((Graphics2D) g);
}
}
EDIT: I spotted a few additional problems with your code: 编辑:我发现您的代码一些其他问题:
FlowLayout
(so it won't manage displaying components at given coordinates). FlowLayout
(这样它将不会管理在给定坐标处的显示组件)。 setPreferredSize(Roundabout.getSurface().getSize());
setPreferredSize(Roundabout.getSurface().getSize());
at the end of the constructor. . 。
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.rotate(Math.toRadians(pedestrianRotation),
pedestrianPosition.x, pedestrianPosition.y);
g2d.drawImage(pedestrian, pedestrianPosition.x,
pedestrianPosition.y, null);
}
surface =new Surface();
surface =new Surface();
should be called inside initUI()
so that it is instanciated on the Event Thread. initUI()
内部initUI()
以便在事件线程上实例化它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.