繁体   English   中英

Java GUI是否由于insertString方法冻结?

[英]Java GUI freezing because of insertString method?

您是否曾经听说过由于反复调用方法javax.swing.Document.insertString而导致GUI冻结?

有我的代码:

private int insertNotation(GameNode startNode, StyledDocument doc, int pos) {

    String s = "";
    int startPos = pos;
    boolean isContinuous = false;

    Style boldStyle, regularStyle, commentStyle, currentNodeStyle, nagStyle, grayStyle;
    grayStyle = notationTextPane.getStyle("gray");
    GameNode currentNode = history.getCurrentGameNode();
    if ((currentNode.isLeaf() && startNode == currentNode.getParent()) || startNode == currentNode) {

    try {
        if (startNode.getComment().length() > 0) {
            s = startNode.getComment() + " ";
            commentStyle.addAttribute("gameNode", startNode);
            doc.insertString(pos, s, commentStyle);
            pos += s.length();
        }
        for (int n = 0; n < startNode.getChildCount(); n++) {
            GameNode node = (GameNode) startNode.getChildAt(n);
            boolean isCurrentNode = (node == currentNode);
            if (node.isLeaf()) {
                if (node.isWhiteMove()) {
                    s = node.getFullMoveNumber() + ". ";
                    boldStyle.addAttribute("gameNode", node);
                    doc.insertString(pos, s, boldStyle);
                    pos += s.length();
                    s = node.getMove();
                    Style style = isCurrentNode ? currentNodeStyle : regularStyle;
                    style.addAttribute("gameNode", node);
                    doc.insertString(pos, s, style);
                    pos += s.length();
                    isContinuous = true;
                } else {
                    if (isContinuous) {
                        s = node.getMove();
                        Style style = isCurrentNode ? currentNodeStyle : regularStyle;
                        style.addAttribute("gameNode", node);
                        doc.insertString(pos, s, style);
                        pos += s.length();
                    } else {
                        isContinuous = true;
                        s = node.getFullMoveNumber() + "... ";
                        boldStyle.addAttribute("gameNode", node);
                        doc.insertString(pos, s, boldStyle);
                        pos += s.length();
                        s = node.getMove();
                        Style style = isCurrentNode ? currentNodeStyle : regularStyle;
                        style.addAttribute("gameNode", node);
                        doc.insertString(pos, s, style);
                        pos += s.length();
                    }
                }
               doc.insertString(pos++, " ", regularStyle);
        }
    } catch (BadLocationException e) {
     e.printStackTrace();
    }
    return pos - startPos;
}

我做了很多简化,但是如您所见,我的“ doc” StyledDocument变量中有许多对insertString()方法的调用。 此StyledDocument对象添加在JTabbedPane中。

我在此处 (在性能分析部分中)已经阅读到javax.swing.Document.insertString方法非常慢(此处每次调用超过1毫秒)。

重复调用可以冻结GUI吗?

每当您在主GUI线程中执行缓慢的操作时,都会冻结GUI。 它根据处理事件进行重绘。 假设您的事件处理代码处于while循环中,将事件从队列中拉出-如果您不从函数中返回,则无法处理下一个事件。

考虑在后台线程中长时间运行或处理缓慢。

请参阅本文: http : //java.sun.com/products/jfc/tsc/articles/threads/threads2.html

考虑使用后台线程来限制向文档中添加文本。 最好使用SwingWorker完成。

首先,我们定义节流队列。 插入文本的请求只会添加到此队列中。 这些请求不必在事件调度线程上。

BlockingQueue<String> toAdd = new LinkedBlockingQueue<String>();
toAdd.add("Some text");
toAdd.add("Some more text");    

接下来,我们调用SwingWorker ,其中后台线程连续轮询队列并将结果以块的形式发布回Event Dispatch线程。

new SwingWorker<Void, String>() {
   // Implementation of 'process' and 'doInBackground' methods to go here.
}.execute();

现在,我们实现doInBackground进行轮询,直到输入队列为空,然后doInBackground将其发布回Event Dispatch线程,以实现更高效的节流。

  public String doInBackground() {
    while (!Thread.interrupted()) {
      List<String> l = new LinkedList<String>();
      String s = toAdd.poll();

      if (s == null) {
        publish(l.toArray(new String[l.size()]));
        l.clear();
      } else {
        l.add(s);
      }
    }

    // Thread interrupted but publish anything pending before returning.
    if (!l.isEmpty()) {
      publish(l.toArray(new String[l.size()]));
    }

    return null;
  }

最后我们执行process 在调用在后台线程上发布之后,在Swing线程上调用它。 我们使用StringBuilderchunks连接在一起,以避免需要在文档中多次插入 (这是此方法的主要优点 )。

  public void process(String... chunks) {
    StringBuilder sb = new StringBuilder();
    for (String chunk : chunks) {
      sb.append(chunk);
    }

    // Insert sb.toString() into buffer HERE
  }

您实际上是看到停滞(没有前进的进度)还是只是非常严重的减速?

我们没有您的完整程序代码,因此尚不清楚,但是开始更改文档时是否已显示您的文档? 每次对insertString的调用不仅会修改文档,还会创建一系列事件,GUI会对此做出反应。

如果本质上是在构建文档,而只想显示最终状态,则可能需要考虑先构建一个新文档,然后再将其添加到文本组件小部件中,然后设置就绪的文档。 这会更加闪烁,但速度要快得多,因为直到使用setDocument将文档添加到小部件之前,您才真正触发事件和更新。

然后,您可以在其他线程上构建文档。

当我使用SwingWorker对象减轻GUI线程时,问题就消失了:对javax.swing.Document.insertString的调用就在此SwingWorker中。

我还遇到了另一个已解决的错误:图形过多,处理过程过多。 在这种情况下,我也使用了SwingWorker。

这是代码:

 new SwingWorker<Void, Void>()
 {
  @Override
  protected Void doInBackground() throws Exception
   {
    visualBoard.update(); // here your method call, deported from the GUI thread. 
    return null;
   }

 }.execute();

谢谢大家这么快的回答!

这实际上可能发生。 这也不是要做太多。 该方法只是挂起(CPU = 0%)。

这是一个测试示例: http : //tinybrain.de/1000816

发生错误时,您将根本看不到框架,并且控制台上的最后一行是“插入”。

这是一个严重的错误,完全可以反对使用JTextPane ...

编辑:我现在也用JTextArea.append复制了冻结! http://tinybrain.de/1000822

似乎总是围绕在AWT线程中创建元素 以前,我只是在main()中创建它们,然后在其中使用附加函数调用SwingUtilities.invokeLater。 这似乎是错误的。

如果我在“ awt {}”块(SwingUtilities.invokeLater的JavaX速记)中创建整个GUI,那么一切都很好,如您在此处看到的: http : //tinybrain.de/1000823

干杯

您应该考虑在线程中运行重复的调用。 那应该为你做。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM