Swing重新打电话

时间:2017-10-12 22:31:28

标签: java multithreading swing

我正在使用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();
}

1 个答案:

答案 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

在EDT上构建新的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()