0

起初我是这样做的:

public SpaceCanvas(){
    new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
        int fcount = 0;

        @Override
        public void run() {
                System.out.println("Update thread started!");
                while(!Thread.interrupted()){
                    fcount++;
                    while(players.iterator().hasNext()){
                        players.iterator().next().update(fcount);
                    }
                    while(entities.iterator().hasNext()){
                        entities.iterator().next().update(fcount);
                    }
                    System.out.println("About to paint");
                    repaint();
                    System.out.println("Done with paints");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
        }
    }).start();
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

在我称之为 SpaceCanvas 的东西的初始化程序中。但是,这不允许创建画布,因此也不允许创建它所在的小程序,因为线程实际上并没有异步运行。然后,我用“.run()”替换了“.start()”,线程只运行了一次,但 SpaceCanvas 完美初始化。

我做错了什么,我该如何解决?

4

2 回答 2

3

我不确定这种代码是否按您期望的方式工作:

while(players.iterator().hasNext()){
    players.iterator().next().update(fcount);

players.iterator()获取players集合的新迭代器。如果集合中有 0 个项目,那么它将是false,但如果有任何项目,您将处于无限循环中,每次都会创建一个新的迭代器。内部的iterator()调用players也会生成另一个新的迭代器对象。

我认为你应该这样做:

Iterator iterator = players.iterator();
while (iterator.hasNext()) {
    iterator.next().update(fcount);
}

这与您的entities循环相同。更好的模式(从 Java 5 开始)是使用for循环:

for (Player player : players) {
    player.update(fcount);
}

此外,如果多个线程正在访问这些集合,它们必须以某种方式synchronized。您可以使用并发集合,也可以确保每次访问(读取和写入)都在一个synchronized块内。

synchronized (players) {
    for (Player player : players) {
        player.update(fcount);
    }
}
...
// down in the outer thread
synchronized (players) {
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

显然,entities遗嘱需要以synchronized相同的方式。

于 2012-05-04T22:20:05.913 回答
1
  1. 在这个千禧年,使用 Swing ( JApplet/JPanel) 而不是 AWT ( Applet/Canvas)
  2. 使用 Swing 时,建立一个每 500 毫秒Timer调用一次的 Swing。repaint()
  3. (使用 Swing/ 时Timer)不要调用Thread.sleep(n)EDT(事件调度线程)。

..你能在 JPanel 上画画吗?

肯定的事。为此,请覆盖该paintComponent(Graphics)方法。你也可以扩展 aJComponent并做同样的事情,但是处理 a 时有一些怪癖,JComponent这使得JPanel扩展成为更好的选择。

另一方面,完全有另一种方法。

  • 创建BufferedImage所需的任何自定义图形所需的大小。
  • 将图像添加到ImageIcon.
  • 将图标添加到JLabel.
  • 将标签添加到 GUI。
  • 在每一个Timer动作上。
    • 调用image.getGraphics()以获取绘图表面。
    • 复制你可能做过的事情paint()paintComponent()
      1. (如果需要)擦除所有以前的绘图。
      2. 绘制当前的自定义渲染。
    • dispose()图像的Graphics实例。
    • 称呼label.repaint()
于 2012-05-04T22:35:58.500 回答