简体   繁体   English

在运行时从另一个类上绘制JPanel

[英]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()设置heightwidth就越高。 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 . 编辑:修改了我的帖子,现在它是一个可运行的示例,您只需要为TrackPedestrian选择自己的图像即可。

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: 编辑:我发现您的代码一些其他问题:

  • Surface.java: Note that, as is, you use the default FlowLayout (so it won't manage displaying components at given coordinates). Surface.java:请注意,照原样使用默认的FlowLayout (这样它将不会管理在给定坐标处的显示组件)。
  • Pedestrian.java: Add setPreferredSize(Roundabout.getSurface().getSize()); Pedestrian.java:添加setPreferredSize(Roundabout.getSurface().getSize()); at the end of the constructor. 在构造函数的末尾。 Replace your paint() method with: 将您的paint()方法替换为:

.

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);
}
  • RoundAbout.java: surface =new Surface(); RoundAbout.java: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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM