从SwingWorker thread-doInBackground()显示消息(Joptionpane)

时间:2017-04-18 10:24:56

标签: java multithreading swing joptionpane swingworker

点击按钮,我正在执行一项长任务。我想显示任务已启动的消息。使用swingworker,JOptionPane创建消息框,但其内容保持空白,直到任务完成。我想我的EDT被阻止,因此除非任务完成,否则GUI不会更新。有没有办法显示这个(swingutils.invokelater不能用,因为我需要在任务开始时显示) 示例代码: -

public class myClass  {
private JFrame frame;
private display1 dis;

class display1 extends SwingWorker<Void,Void>
{
    public Void doInBackground() throws InterruptedException
    {
    JOptionPane.showMessageDialog(null,
                "Task Started");
        return null;
    }
}
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                myClass window = new myClass();
                window.frame.setVisible(true);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


 public myClass() {
    initialize();
}


private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            dis=new display1();
            dis.execute();

         System.out.println("starting");
           for(int i=0;i<10000;i++)
               System.out.println("this is " +i);// Long task


         System.out.println("Finished");
        }
    });
    btnNewButton.setBounds(166, 228, 89, 23);
    frame.getContentPane().add(btnNewButton);

}
}

2 个答案:

答案 0 :(得分:2)

因为SwingWorker通知事件调度线程上的任何PropertyChangeListener,所以只需侦听绑定属性state。可能的values包括DONEPENDINGSTARTED。此TaskListener是写入控制台的示例,但在propertyChange()的实现中更新标签是完全安全的。模态对话是允许的,但是多余的。

答案 1 :(得分:0)

invokeLater(Runnable);中运行的任何内容都会发送到Event Dispatch Thread“gui-thread”。您的方法initialize()在EDT中运行即可,但您需要记住,在EDT中正在处理与UI相关的任何操作。因此,如果用户单击按钮,则在EDT中执行ActionListener代码。在EDT中执行的任何长时间运行的任务都会阻止处理另一个UI事件。因此,您需要将“长任务”移动到单独的线程e。 G。到SwingWorker

如果你需要在运行任务之前显示一些东西,只需在调用swingWorker.execute();之前放置它(确保给定代码在EDT中执行):

button.addActionListener(new ActionListener() {
    @Override public void actionPerformed(ActionEvent arg0) {
        // we are are in EDT = dialog will be displayed without any problems
        JOptionPane.showMessageDialog(null, "About to start");
        // executes SwingWorker's doInBackground task
        new BackgroundTask().execute(); 
    }
});

以下代码说明了如何使用SwingWorker

class BackgroundTask extends SwingWorker<
        String/*background task's result type*/, 
        Integer/*inter-step's result type*/
        >
{
    /**
     * This method is designed to perform long running task in background 
     * i. e. in "non-EDT" thread = in SwingWorker thread.
     * 
     * After method is completed, {@link #done()} is called, which is 
     * executed in "EDT" (gui-thread).
     * 
     * Note, you can {@link #publish(Integer)} progress to {@link #process(List<V> chunks)} 
     * which is executed in "EDT" (gui-thread).
     *  
     * You can also use {@link SwingUtilities#invokeLater(Runnable)}
     * to send "message" to "EDT" which contains code to be executed
     * This is similar to {@link #publish(Object)} except not-processed-yet 
     * messages are not collected and processed all at once like in 
     * {@link #publish(Object)} case.
     */
    @Override
    protected String doInBackground() throws Exception {
        // or you can put JOptionPane.showMessageDialog(null, "About to start"); 
        // in ActionListener before calling swingWorker.execute();
        SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null, "About to start"));
        // System.out.println("starting");
        for(int i = 0; i < 10000; i++) {
            // System.out.println(i);
            publish(i);
        }
        // result of the background task
        return "Task completed"; 
    }

    /**
     * Method is executed in "EDT" after calling {@link #publish(Integer)}. 
     * 
     * This is the right place to update GUI about inter-step result.
     * 
     * Note, this method is not executed immediately after calling {@link #publish(Integer)}, 
     * since EDT can process at this time sime other GUI tasks.
     * Therefore, list contains all inter-step results send from SwingWorker 
     * to EDT which were not processed yet. 
     */
    @Override
    protected void process(List<Integer> chunks) {
        for (int number : chunks) {
            textArea.append(number + "\n");
        }
    }

    /**
     * Method is executed in "EDT" after {@link #doInBackground()} is finished.
     * This is the right place to update GUI about final result.
     */
    @Override
    protected void done() {
        String result = get(); // returns result of the doInBackground();
        JOptionPane.showMessageDialog(null, result);
    }
}