【问题标题】:Show message(Joptionpane) from SwingWorker thread- doInBackground()显示来自 SwingWorker 线程的消息(Joptionpane) - doInBackground()
【发布时间】:2017-04-18 10:24:56
【问题描述】:

点击一个按钮,我正在运行一个很长的任务。我想显示任务已开始的消息。使用 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);

}
}

【问题讨论】:

  • display1 是什么?你在 EDT 的上下文中运行一个很长的任务,这解释了为什么你的 UI 是空白的
  • display1 是实现 SwingWorker 的类的名称。我知道它不起作用的原因。我所要求的只是一种显示任务已启动并同时执行任务的对话的方法(该任务包含操作某些 GUI 组件)
  • 考虑提供一个runnable example 来证明您的问题。这不是代码转储,而是您正在做的事情的一个例子,它突出了您遇到的问题。这将导致更少的混乱和更好的响应
  • 上面的程序非常清晰易懂。我发布了完整的代码以获得更好的可见性/理解,并且代码本身非常简单和简短。如果您没有任何积极的贡献,请停止不必要的评论
  • 对不起,我试图了解您的问题以帮助您找到解决方案,但 for(int i=0;i&lt;10000;i++) 将阻止可能阻止 UI 更新的 EDT,但我想这无关紧要不帮忙,那我很抱歉

标签: java multithreading swing joptionpane swingworker


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    invokeLater(Runnable); 中运行的任何内容都会发送到Event Dispatch Thread“gui-thread”。您的方法initialize() 在 EDT 中运行没问题,但您需要记住,任何与 UI 相关的操作都在 EDT 中处理。因此,如果用户单击按钮,ActionListener 代码将在 EDT 中执行。在 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);
        }
    }
    

    【讨论】:

    • “我想显示任务已开始的消息”
    • @MadProgrammer 写的时候忘记了,我会更新我的答案。
    • 还要注意无法到达安全点的繁忙循环,对于example
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多