起初我这样做了:
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的东西的初始化器中。 但是,这不允许创建画布,因此创建它所在的applet,因为Thread不会实际异步运行。然后,我用“.run()”替换了“.start()”,线程只运行了一次,但SpaceCanvas完全初始化。
我做错了什么,我该如何解决这个问题?
答案 0 :(得分: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
。
答案 1 :(得分:1)
JApplet/JPanel
)而不是AWT(Applet/Canvas
)Timer
的Swing repaint()
。 Timer
时)请勿在EDT(事件调度线程)上调用Thread.sleep(n)
。..你可以在JPanel上画画吗?
当然可以。为此,请覆盖paintComponent(Graphics)
方法。您也可以扩展JComponent
并执行相同的操作,但是处理JComponent
会有一些怪癖,这使得JPanel
成为更好的扩展选择。
另一方面,完全有另一种方法。
BufferedImage
。ImageIcon
。JLabel
。Timer
行动。
image.getGraphics()
以获取绘图表面。paint()
或paintComponent()
中所做的工作
dispose()
Graphics
图片实例。label.repaint()