Java 使用SwingWorker更新GUI

Java 使用SwingWorker更新GUI,java,swing,concurrency,swingworker,Java,Swing,Concurrency,Swingworker,昨天我在这里发布了一个关于在使用scheduledexecutorservice时防止UI冻结的问题,大多数人建议使用SwingWorker而不是scheduledexecutorservice。然而,从那以后,我一直在努力弄清楚SwingWorker线程在我的案例中是如何工作的 我有以下伪代码: createGraph(){ if(rule1) n = new Node() graph.add(n) animateGraph() createGraph()

昨天我在这里发布了一个关于在使用scheduledexecutorservice时防止UI冻结的问题,大多数人建议使用SwingWorker而不是scheduledexecutorservice。然而,从那以后,我一直在努力弄清楚SwingWorker线程在我的案例中是如何工作的

我有以下伪代码:

createGraph(){
  if(rule1)
    n = new Node()
    graph.add(n)
    animateGraph()
    createGraph()
  if(rule2)
    ...
我有一个递归算法,它根据某些规则创建一个图,我想在匹配规则并向图中添加新的顶点/边时更新UI。我的问题是,每当添加新节点/边时,如何显示图形?这应该发生在animateGraph()方法中,当它点击此方法时,它应该更新实际的UI,最好等待1500毫秒,直到构建整个图形为止

我尝试创建一个SwingWorker线程。在本例中,它不显示图形创建的中间步骤,只显示最终图形。首先,它执行对doInBackground()的所有调用,然后转到done()

注意:每次创建新的顶点/边时,我都会创建一个新的SwingWorker线程,因为我读到doInBackground()只调用一次

private void animateGraph() {
    swingWorker = createRunnable();
    swingWorker.execute();
}

private void displayGraph() {
    JPanel.add(graph);
}

private SwingWorker<Object, Object> createRunnable() {
    swingWorker = new SwingWorker<Object, Object>() {

        @Override
        protected Void doInBackground() throws Exception {
            System.out.println("Start sleeping.. " + new Date());
            Thread.sleep(1500);
            publish(new NodeTuple(new Node("A"), new Node("B")));
            return null;
        }

        protected void process(List<NodeTuple> chunks) {
            System.out.println("In process..     " + new Date());
            NodeTuple nodeTuple = chunks.get(chunks.size() - 1);
            graph.addVertex(nodeTuple.source);
            graph.addVertex(nodeTuple.target);
            checkIfToAddEdge(nodeTuple.source, nodeTuple.target);
            createDiagram();
        }

        }
    };
    return swingWorker;
}
private void animateGraph(){
swingWorker=createRunnable();
swingWorker.execute();
}
私有void displayGraph(){
JPanel.add(图);
}
私有SwingWorker createRunnable(){
swingWorker=新swingWorker(){
@凌驾
受保护的Void doInBackground()引发异常{
System.out.println(“开始睡眠..”+新日期());
睡眠(1500);
发布(新节点耦合(新节点(“A”)、新节点(“B”));
返回null;
}
受保护的无效进程(列表块){
System.out.println(“进程中..”+新日期());
NodeTuple NodeTuple=chunks.get(chunks.size()-1);
graph.addVertex(nodeTuple.source);
addVertex(nodeTuple.target);
CheckIftLoadDedge(nodeTuple.source,nodeTuple.target);
createDiagram();
}
}
};
返回swingWorker;
}

编辑:我更新了doInBackground()和process()方法。然而,我仍然没有得到我真正想要的。不显示中间步骤,只显示最终图形。

您可能应该使用
SwingWorker
发布过程
API(参见代码的第二个示例)

这将允许您递归地在EDT之外创建节点,然后发布与规则匹配的新节点,最后在EDT上处理这些节点以进行显示或动画


添加动画需要它自己的线程,我建议您将其作为一项单独的任务添加,但至少您应该能够在将新节点添加到图形中时看到它们显示。

您可能应该使用
SwingWorker
发布
/
过程
API(请参见代码的第二个示例)

这将允许您递归地在EDT之外创建节点,然后发布与规则匹配的新节点,最后在EDT上处理这些节点以进行显示或动画


添加动画需要它自己的线程,我建议您将其作为一项单独的任务添加,但至少您应该能够看到添加到图形中的新节点出现。

要查看中间步骤,您必须
publish()
在创建和
process()时发布每个新的
节点
在事件调度线程上显示,如中所示

类FlipTask扩展SwingWorker{
@凌驾
受保护列表doInBackground(){
…
发布(新节点);
…
}
受保护的无效进程(列表){
//将每个新节点添加到视图中
}
}

要查看中间步骤,必须在创建每个新的
节点时
publish()
,并在事件调度线程上
process()
它,如中所示

类FlipTask扩展SwingWorker{
@凌驾
受保护列表doInBackground(){
…
发布(新节点);
…
}
受保护的无效进程(列表){
//将每个新节点添加到视图中
}
}

通过将每个新节点添加到视图中,您是想更新UI吗?如果是,我可以直接这样做,还是必须使用SwingUtilities.invokeLater(..)?是的;大多数图形库都有某种模型,允许您添加新节点;这会更新视图;我使用。无需
invokeLater()
;`process()在EDT上运行。是否可以在发布新节点之前调用Thread.sleep()?是的,在
doInBackground()中调用
sleep()
完全可以
;我看到的许多示例都是这样做的,以调整动画速度或模拟延迟。通过将每个新节点添加到视图中,您的意思是更新UI吗?如果是,我可以直接这样做,还是必须使用SwingUtilities.invokeLater(..)?是的;大多数图形库都有某种模型,允许您添加新节点;这会更新视图;我使用。无需
invokeLater()
;`process()在EDT上运行。在发布新节点之前是否可以调用Thread.sleep()?是的,在
doInBackground()中
sleep()
完全可以
;我看到的许多示例都是通过调整动画的速度或模拟延迟来实现的。
class FlipTask extends SwingWorker<List<Node>, Node> {
    @Override
    protected List<Node> doInBackground() {
        …
        publish(new (Node);
        …
    }

    protected void process(List<Node> list) {
        // add each new Node to the view
    }
}