【问题标题】:Updating GUI with SwingWorker使用 SwingWorker 更新 GUI
【发布时间】:2016-01-25 13:40:25
【问题描述】:

我昨天在What should I do in order to prevent the UI from freezing(scheduledexecutorservice) 发布了一个关于在使用 scheduleexecutorservice 时防止 UI 冻结的问题,大多数人建议使用 SwingWorker 而不是 scheduleexecutorservice。但是,从那时起,我一直在试图弄清楚 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;
}

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

【问题讨论】:

    标签: java swing concurrency swingworker


    【解决方案1】:

    您可能应该使用SwingWorkerpublish/process API(有关代码,请参见SwingWorker API doc 的第二个示例)。

    这将允许您在 EDT 之外递归地创建节点,然后 publish 匹配您的规则的新节点,最后在 EDT 上 processing 这些节点用于显示或动画。

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

    【讨论】:

      【解决方案2】:

      要查看中间步骤,您必须 publish() 每个新的 Node 创建它并在事件调度线程上 process() 它,就像它们在 Tasks that Have Interim Results 中显示的那样。

      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
          }
      }
      

      【讨论】:

      • 通过将每个新节点添加到视图中,您的意思是更新 UI 吗?如果是这样,我可以直接这样做还是必须使用 SwingUtilities.invokeLater(....) ?
      • 是的;大多数图形库都有某种模型,可让您添加新节点;这会更新视图;我使用jfreechart。无需invokeLater(); `process() 在 EDT 上运行。
      • 是否可以在发布新节点之前调用 Thread.sleep()?
      • 是的,在您的doInBackground() 中输入sleep() 完全可以;我看到的很多例子都是为了调整动画或模拟延迟。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多