简体   繁体   English

如何从 EDT 将 object 交付给长期运行的 SwingWorker?

[英]How to deliver object to a long-running SwingWorker from the EDT?

How can the EDT communicate to an executing SwingWorker ? EDT 如何与正在执行的SwingWorker通信? There a lot of ways for the SwingWorker to communicate information back to the EDT - like publish/process and property changes but no defined way (that I have seen) to communicate in the other direction. SwingWorker有很多方法可以将信息传回 EDT——比如发布/处理和属性更改,但没有定义的方式(我见过)在另一个方向上进行通信。 Seems like good old Java concurrent inter-thread communication would be the way to go via wait() and notify() .似乎旧的 Java 并发线程间通信将是通过wait()notify()到 go 的方式。 This doesn't work.这行不通。 I'll explain later.我稍后会解释。 I actually got it to work but it uses an ugly polling mechanism.我实际上让它工作,但它使用了一个丑陋的轮询机制。 I feel like there should be a better way.我觉得应该有更好的方法。 Here is the process that I am trying to accomplish:这是我要完成的过程:

  1. From the main Swing UI (EDT) a user starts a SwingWorker long-running task (the engine).用户从主Swing UI (EDT) 启动SwingWorker长时间运行的任务(引擎)。
  2. At some point the engine needs information from the EDT so it communicates this back to the EDT.在某些时候,引擎需要来自 EDT 的信息,因此它将这些信息传回给 EDT。 this could be done through publish/process update of a visible UI component.这可以通过发布/处理可见 UI 组件的更新来完成。 Importantly, this step DOES NOT block the EDT because other things are also going on.重要的是,此步骤不会阻止 EDT,因为其他事情也在发生。
  3. The engines blocks waiting for an answer.引擎阻塞等待答案。
  4. At some point the user notices the visual indication and provides the required information via some UI (EDT) functionality - like pressing a Swing button.在某些时候,用户会注意到视觉指示并通过某些 UI (EDT) 功能提供所需的信息 - 例如按下Swing按钮。
  5. The EDT updates an object on the engine. EDT 更新引擎上的 object。 Then "wakes up" the engine.然后“唤醒”引擎。
  6. The engine references the updated object and continues to process.引擎引用更新后的 object 并继续处理。

The problem I have with wait() / notify() is that in step 3 any invocation of wait() in doInBackground() causes the done() method to be immediately fired and the SwingWorker to be terminated.我对wait() / notify()的问题是,在第 3 步中, doInBackground()中对wait()的任何调用都会导致done()方法立即被触发并终止SwingWorker I was able to get the above process to work by using an ugly sleep() loop in doInBackground() :通过在doInBackground()中使用丑陋的sleep()循环,我能够使上述过程正常工作:

for (;;)
{
    Thread.sleep(10);

    if (fromEDT != null)
    {
        // Process the update from the EDT
        System.out.println("From EDT: " + fromEDT);
        fromEDT = null;
        break;
    }
}

What this really is that in step 5 the engine wakes itself up and checks for updates from the EDT.这实际上是在第 5 步中引擎将自己唤醒并检查来自 EDT 的更新。

Is this the best way to do this?这是最好的方法吗? I kind of doubt it.我有点怀疑。

The following is an mre demonstrating a SwingWorker paused and waiting for user's input:以下是一个演示SwingWorker已暂停并等待用户输入的 mre:

import java.awt.*;
import java.util.List;
import javax.swing.*;

public class SwingWorkerWaitDemo {

    public static void creategui(){

        JFrame f = new JFrame("SwingWorker wait Demo");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.add(new MainPanel());
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        creategui();
    }
}

class MainPanel extends JPanel {

    private static final String BLANK = "               ";

    private MyWorker swingWorker;
    private final JLabel output, msg;
    private final JButton start, stop, respond;

    MainPanel() {
        setLayout(new BorderLayout(2, 2));
        start = new JButton("Start");
        start.addActionListener(e->start());
        stop = new JButton("Stop");
        stop.setEnabled(false);
        stop.addActionListener(e->stop());
        JPanel ssPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
        ssPane.add(start); ssPane.add(stop);
        add(ssPane, BorderLayout.PAGE_START);

        output = new JLabel(BLANK);
        JPanel outputPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
        outputPane.add(output);
        add(outputPane, BorderLayout.CENTER);

        msg = new JLabel(BLANK);
        respond = new JButton("Respond");
        respond.addActionListener(e->respond());
        respond.setEnabled(false);
        JPanel responsePane = new JPanel();
        responsePane.add(msg); responsePane.add(respond);
        add(responsePane, BorderLayout.PAGE_END);
    }

    @Override
    public Dimension getPreferredSize(){
        return new Dimension(400, 200);
    }

    private void start() {
        start.setEnabled(false);
        stop.setEnabled(true);
        swingWorker = new MyWorker();
        swingWorker.execute();
    }

    private void stop() {
        stop.setEnabled(false);
        swingWorker.setStop(true);
    }

    private void message(String s){
        msg.setText(s);
    }

    private void clearMessage(){
        msg.setText(BLANK);
    }

    private void askForUserResponse(){
        respond.setEnabled(true);
        message("Please respond " );
    }

    private void respond(){
        clearMessage();
        respond.setEnabled(false);
        swingWorker.setPause(false);
    }

    class MyWorker extends SwingWorker<Integer, Integer> {

        private boolean stop = false;
        private volatile boolean pause = false;

        @Override
        protected Integer doInBackground() throws Exception {

            int counter = 0;

            while(! stop){
                publish(counter++);
                if(counter%10 == 0) {
                    pause = true;
                    askForUserResponse();
                    while(pause){   /*wait*/ }
                }
                Thread.sleep(500);
            }
            return counter;
        }

        @Override
        protected void process(List<Integer> chunks) {
            for (int i : chunks) {
                output.setText(String.valueOf(i));
            }
        }

        @Override
        protected void done() {
            message("All done");
        }

        void setStop(boolean stop) {
            this.stop = stop;
        }

        void setPause(boolean pause) {
            this.pause = pause;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在EDT之外执行长时间运行的正确方法是什么? - What is the correct way to perform long-running operation outside the EDT? 为什么SwingWorker不将对象返回给EDT? - Why is SwingWorker not returning an object to the EDT? 处理长时间运行的EDT任务(fi TreeModel搜索) - Handle long-running EDT tasks (f.i. TreeModel searching) 如何处理长时间运行不稳定的服务器 - How to handle long-running unstable server 如何执行长时间运行的任务? - How to execute long-running tasks? Java - SwingWorker - 我们可以从其他SwingWorker而不是EDT调用一个SwingWorker - Java - SwingWorker - Can we call one SwingWorker from other SwingWorker instead of EDT 如何从另一个servlet中杀死一个长时间运行的servlet进程? - How do I kill a long-running servlet process from another servlet? sshj:如何在执行命令时从长时间运行的命令中读取InputStream - sshj: how to read InputStream from long-running command while command is executing 如何根据从其他线程中长时间运行的任务收到的​​通知更新JTable? - How do I update a JTable based on a notification received from a long-running task in other thread? 从Apache ServiceMix内部启动长时间运行的过程 - Starting long-running process from within Apache ServiceMix
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM