我正在使用Java Swing来显示递归解决的问题。
每次遇到问题时我都会重新绘制我的GUI(如果它通过queenSafe
方法后解决了)。
但是我在这里遇到了问题。
据我所知,事件处理程序和图形由同一个线程控制,因此我不能告诉线程在设置标志时休眠以更新GUI。所以创建一个新线程最好?但不太确定如何实施它。到目前为止,我正试图用一个标志告诉另一个线程重绘。但这似乎给了我一个无限循环。有什么建议吗?
public void queensProblem(){
this.guiUpdate();
boolean solved = solveQueenBlindSearch(0);
if(!solved){
JOptionPane.showMessageDialog(gui, "Sorry, but this is not solvable");
}
}
boolean solveQueenBlindSearch(int col)
{
if (col >= cb.queens)
return true;
for (int row = 0; row < cb.columns; row++)
{
if (queenSafe(row, col))
{
cb.board[row][col].piece = new Queen();
this.flag = true;
if (solveQueenBlindSearch(col + 1) == true)
return true;
cb.board[row][col].piece = null;
}
}
return false;
}
void guiUpdate() {
new Thread() {
public void run() {
while(true){
if(flag){
mainLayout.removeAll();
mainLayout.add(searches);
JPanel newChessboard = cb.drawChessboard();
mainLayout.add(newChessboard);
mainLayout.repaint();
flag = false;
}
}
}
}.run();
}
答案 0 :(得分:1)
正如MadProgrammer指出的那样,你可以使用SwingWorker
来促进这种行为。但是,我提供了一个小例子(不是特定于您的程序),演示了如何在后台线程上更新代理并更新事件调度线程(EDT)上的GUI。
请注意,这只是您可以采用的一种方法。
该示例包括两个类,GuiWorker
是发生所有线程处理的地方,ExampleFrame
使用GuiWorker
来提供示例。
<强> GuiWorker 强>
这是一个抽象类,它定义执行过程,在正确的线程上运行相关任务。它有两个必须实现的抽象方法backgroundProcess()
和postExecute()
。
backgroundProcess()
不会在EDT上运行,而是在后台线程中运行。这是在postExecute()
postExecute()
将在EDT上运行,并且应该在后台任务完成后更新GUI。
import javax.swing.SwingUtilities;
public abstract class GuiWorker {
public abstract void backgroundProcess(); // method called on background thread
public abstract void postExecute(); // method called on EDT
public void execute() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Running backgroundProcess() on EDT: " + SwingUtilities.isEventDispatchThread());
// Execute backgroundProcess() on this background thread
backgroundProcess();
// When backgroundProcess() pops, run postExecute() on the EDT
System.out.println("End of background process.");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Running postExecute() on EDT: " + SwingUtilities.isEventDispatchThread());
postExecute();
}
});
}
}).start(); // start background thread
}
}
<强> ExampleFrame 强>
这只是一个带标签的小型(并且不起眼!)GUI。此处还定义了main(String[] args)
方法,以减少此示例中的类数。
main(String args)
方法(入口点)将使用ExampleFrame
SwingUtilities.invokeLater(Runnable)
实例
为简单起见,所有内容都在构造函数中执行。使用名为JLabel
的{{1}}设置并显示GUI,该output
最初包含文本&#39; Initial &#39;以及使用{{1}做一些后台任务。在这种情况下,它将执行10次迭代的while循环,将GuiWorker
输出到控制台(每次迭代时增加1)。每次迭代在500ms的后台线程上有一个短暂停顿。完成此操作后,i
名为JLabel
的{{1}}将更新为&#39; 已完成&#39;。
output
如果GUI更新需要执行后台任务期间的数据,则在将import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class ExampleFrame extends JFrame {
private JLabel output = new JLabel("Initial");
public static void main(String[] args) {
// Construct and show a new JFrame (ExampleFrame) on the EDT
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ExampleFrame();
}
});
}
public ExampleFrame() {
System.out.println("Running ExampleFrame() constructor on EDT: " + SwingUtilities.isEventDispatchThread());
// Setup GUI
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(output);
pack();
setVisible(true);
// Implement the abstract methods of GuiWorker and invoke execute() to run
new GuiWorker() {
@Override
public void backgroundProcess() {
// To be run on a background thread
int i = 0;
// iterate 10 times, sleeping for 500 ms
// printing i to the console
while (i < 10) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(i);
i++;
}
}
@Override
public void postExecute() {
// when the backgroundProcess has finished
// update the output JLabel on the EDT
output.setText("Finished");
}
}.execute(); // invoke execute to start the worker
}
}
实现为匿名类时可以始终引入类成员字段,否则GuiWorker
可以访问这些字段。或者,可以重新设计postExecute()
以允许GuiWorker
返回一些数据,然后将这些数据作为参数传递给backgroundProcess()
。