【问题标题】:Draw on JPanel from another class at runtime在运行时从另一个类中绘制 JPanel
【发布时间】:2015-05-19 10:36:06
【问题描述】:

我有一个类 Roundabout(JFrame)、Surface(JPanel) 和 Spawn。在 Surface paintComponent 我已经画了一些红绿灯,因为它们总是在环形交叉路口。但我也想在运行时绘制组件。所以我在 JFrame 中添加了一个 mousePressed 事件,我在这里调用的方法最终从 Spawn.java 调用了spawnPedestrian,因为println,我可以看到这一点。但是当spawnPedestrian 被调用时,什么都没有画!如果我在 Surface 类中创建一个行人并绘制它,它就可以工作。我怎样才能使spawnPedestrian 工作?我尝试包含最小代码 sn-p(见下文)。

human.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);
}

编辑:以为我通过将Surface 布局设置为null 并使用setBoundsPedestrian 解决了这个问题。但是我将图像向右移动得越多,我必须在setBounds()中设置heightwidth就越高。谁能帮忙?

编辑:修改了我的帖子,现在它是一个可运行的示例,您只需为TrackPedestrian 选择自己的图像。

编辑:一个复制粘贴操作来添加代码和图像。

【问题讨论】:

  • Surface 使用哪种布局?你能用标准的JButton 替换Pedestrian 实例吗? Roundabout.getSurface().add(new JButton("")); 看看有没有上色?
  • 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短、自包含、正确示例)。
  • @AndrewThompson 我不知道我可以删除什么,这是我认为的最低限度,即使它仍然是很多代码。
  • @Rupak 我不使用Surface 的布局。我试过你的建议来添加一个JButton,它被涂在顶部中心。但是Pedestrian 不会被绘制。有什么解决方案的想法吗?
  • “我不知道我可以删除任何东西” 这不是(必然)关于“删除”任何东西。我注意到缺少TrafficLight,因此代码无法编译。因此,它不能被视为运行时问题的示例。此外,虽然 MCVE/SSCCE 可以是多个类,但它必须是单个源文件(其余类从 public 降级并使用 main 方法粘贴在源代码之后)。再次阅读 SSCCE 链接。

标签: java swing


【解决方案1】:

当您编写Roundabout.getSurface().add(p); 时,您正在向JPanel 对象添加一个JComponent。 JPanel 必须有一个布局来显示子组件。默认情况下,这是FlowLayout(请参阅doc)。 FlowLayout 旨在连续显示组件旁边的其他组件。它不支持在任意坐标显示组件。

我不确定为什么不显示行人,但原因可能是它们的维度为 0x0。您可以使用以下方法轻松检查:

p.setPreferredSize(new Dimension(50,50));

根据您的需要,您可以采用不同的方法:Surface 可以是一个简单的 Canvas,而不是扩展 JPanel,它包含一个“Paintables”列表,例如行人。在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);

   }

}

编辑:我发现您的代码存在一些其他问题:

  • Surface.java:请注意,您使用默认的FlowLayout(因此它不会管理在给定坐标处显示组件)。
  • Pedestrian.java:在构造函数末尾添加setPreferredSize(Roundabout.getSurface().getSize());。将您的 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(); 应在 initUI() 内部调用,以便在事件线程上实例化。

【讨论】:

  • 我试过setPrefferedSizePedestrian 仍然不可见。以及为什么我必须将Surface 更改为Canvas 我尝试了该解决方案但没有绘制任何内容
  • 找到解决办法见我的帖子
  • Canvas 背后的想法是您可能不需要像 JPanel 这样的容器。 Canvas 足以绘制形状和图像。你能尝试在 Surface.java 中硬编码一个行人吗?这样您就可以查看是行人显示问题还是动态显示问题。
  • 尝试了您的建议,但仍然没有绘制Pedestrian
  • 再试一次:问题出在行人的大小,太小了:我更新了我的帖子:setPreferredSize(Roundabout.getSurface().getSize()); 这样你就确定无论图像被绘制,它都会不会被 Pedestrian JComponent 的大小裁剪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
相关资源
最近更新 更多