我正在为一个项目制作国际象棋程序。我正在尝试将移动历史记录框添加到主板的一侧。移动历史记录工作正常,数据被正确发送到文本区域,但是当AI考虑移动时,JTextArea中的文本消失了。
public void aiMove(){
if (!playing){ return; }
paintImmediately(0,0,totalX,totalY);
ai = eve.getMove(chess,wtm,aiOut); //text disappears here
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
writeMove(ai); //updates move history, text reappears here
playing = stillPlaying();
repaint();
}
private void writeMove(Move move){
char c = "abcdefgh".charAt(7-move.fromY);
char h ="abcdefgh".charAt(7-move.toY);
String s = Character.toString(c)+(move.fromX+1)+" - "+Character.toString(h)+(move.toX+1)+" ";
if (!wtm){
String q = chess.getFullMove()+". "+s+" ";
moves.setText(moves.getText()+q);
}
else {
moves.setText(moves.getText()+s+"\n");
}
}
这是正在发生的事情的打印屏幕。 http://s13.postimage.org/mh7hltfk7/JText_Area_disappear.png
解决的 感谢所有回复。我改变了aiMove(),所以它创建了一个线程。这就是我所做的。
尝试#3 ...挥杆对我来说仍然很陌生。我不想将writeMove改为getMove,否则我将不得不稍微改写一下。由于项目基本完成,我试图避免尽可能多的工作:) 无论如何,GUI完全是可选的,我只是为了好玩,并尝试学习一些摆动。
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}
它还修复了我之前遇到的一个问题,因为如果我按下'a'键(强制移动),它会排队许多强制ai移动。现在,这不会发生。
答案 0 :(得分:6)
问题是您的AI思维是CPU密集型/耗时的,因此它被视为长时间运行的任务。您不应该在GUI事件调度线程上执行长时间运行的任务,因为这会导致UI看起来被冻结,因此只在任务完成后显示更新。
幸运的是,您可以使用两种不同的方法:
SwingWorker子类可以定义一个完成的方法,即 当事件调度线程在后台自动调用 任务完成了。
SwingWorker实现了java.util.concurrent.Future。 此接口允许后台任务提供返回值 另一个线程。此界面中的其他方法允许取消 后台任务和发现后台任务是否有 已完成或被取消。
后台任务可以提供 通过调用SwingWorker.publish导致的中间结果 要从事件派发线程调用的SwingWorker.process。
后台任务可以定义绑定属性。对这些的改变 属性触发事件,导致事件处理方法 在事件派发线程上调用。
或者为AI思考创建单独的Thread
并在setText
SwingUtilities.invokeLater(...);
Thread t=new Thread(new Runnable() {
@Override
public void run() {
}
});
t.start();
<强>更新强>
在阅读MadProgrammers评论(+1给它)之后,请记得通过SwingUtilities.invokeLater(..)
块在EDT上创建/操作GUI / Swing组件。您可以在其上阅读更多内容here。
更新2:
编辑正在扼杀这一点,SwingUtilitites
块中对EDT的唯一调用应该是setText
或至少只能操纵Swing组件的代码,即
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){ //originally initialized by constructor
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}