【问题标题】:DocumentListener slows down Document.setCharacterAttributes method?DocumentListener 减慢 Document.setCharacterAttributes 方法?
【发布时间】:2011-06-03 19:03:55
【问题描述】:

这是我在这个网站上的第一个问题,虽然不是我第一次进入以清除我的疑问,很棒的网页。 :)

我正在编写一个突出显示 JTextPane 中代码的 Java 程序,并且我正在更改突出显示的方式。我正在使用 JTabbedPane 让用户同时编辑多个文件,并且我曾经使用 Timer 执行文档突出显示,现在我构建了一个在单独线程中运行的突出显示队列并实现了一个 DocumentListener 队列发生更改时的文档。

但是我有一个非常大的问题,如果我通过 DocumentListener 添加文档,突出显示过程需要很长时间,而如果我通过直接从 JTextPane 获取文档将其添加到主类中,则只需几个毫秒。 我在我的代码中执行了多个基准测试,发现从 DocumentListener 添加文档时需要花费大量时间执行的是方法 Document.setCharacterAttributes()。

下面是通过 DocumentListener 添加文档的方法:

// eventType: 0 - insertUpdate / 1- removeUpdate
private void queueChange(javax.swing.event.DocumentEvent e, int eventType){
    StyledDocument doc = (StyledDocument) e.getDocument();
    int changeLength = e.getLength();
    int changeOffset = e.getOffset();
    int length = doc.getLength();
    String title = (String) doc.getProperty("title");

    String text;
    try {
        text = doc.getText(0, length);

        if (changeLength != 1) {
            Element element = doc.getDefaultRootElement();
            int startLn = element.getElement(element.getElementIndex(changeOffset)).getStartOffset();
            int endLn = element.getElement(element.getElementIndex(changeOffset + changeLength)).getEndOffset() - 1;

            Engine.addDocument(doc, startLn, endLn, title, text);
        } else {
            if(eventType == 1){
                changeOffset = changeOffset - changeLength;
            }
            int startLn = text.lastIndexOf("\n", changeOffset) + 1;
            int endLn = text.indexOf("\n", changeOffset);

            if (endLn < 0) {
                if (length != startLn) {
                    endLn = length;

                    Engine.addDocument(doc, startLn, endLn, title, text);
                }
            } else if (startLn != endLn && startLn < endLn) {
                Engine.addDocument(doc, startLn, endLn, title, text);
            }
        }
    } catch (BadLocationException ex) {
        Engine.crashEngine();
    }
}

如果我用这种方法添加一个有 2k 行的文档,高亮整个文档大约需要 1900 毫秒,而如果我使用插入符号监听方法将文档添加到高亮队列中,大约需要 500 毫秒。

这是插入符号侦听方法的一部分,用于在加载整个文档时突出显示它们:

if (loadFile == true) {
    isKey = false;
    doc = edit[currentTab].Editor.getStyledDocument();
    try {
        Highlight.addDocument(doc, 0, doc.getLength(),
                Scripts.getTitleAt(currentTab), doc.getText(0, doc.getLength()));
    } catch (BadLocationException ex) {
        ex.printStackTrace();
    }
    loadFile = false;
}

注意:Highlight/Engine.addDocument() 方法有五个参数:(StyledDocument doc,int start, int end, String tabTitle, String docText)。 start 和 end 都表示需要突出显示的区域。

我将感谢与此问题相关的任何帮助,因为我已经尝试解决了几天,但我在 Internet 上找不到类似的东西。 :(

顺便说一句,有人知道 Document.setCharacterAttributes 和 Document.setParagraphAttributes 之间的实际区别吗? :P

【问题讨论】:

    标签: java swing jtextpane documentlistener


    【解决方案1】:

    也许您的代码中有某种递归导致了问题。使用 DocumentEvent,您应该只担心添加和删除。您无需担心更改,因为这些是属性更改。

    也许您添加了一些安排突出显示的文本,但是当您更改文本的属性时,您安排了另一个突出显示任务。

    【讨论】:

    • 感谢您的回复,但我忽略了 changedUpdate 方法,因为用户无权访问文本属性,因此当该方法触发时,无需执行任何操作。只有当 insertUpdate 或 removeUpdate 被触发并且我使用的 highlight 方法通过设置 Document 的一部分的字符属性来突出显示文本时,突出显示才会排队,因此该方法不会插入更多文本。
    【解决方案2】:

    您可以尝试设置一个标志来指示是用户更改还是您的 API 更改。在 Engine.addDocument() 的开头将标志设置为 API 状态,并在更改完成后将其重置。 在您的侦听器中检查标志并跳过 API 的更改。 您写了“我使用通过设置文档的一部分的字符属性来突出显示文本,因此该方法不会插入更多文本”。我不确定它不会插入文本。例如。您有“这是一个粗体文本”,然后选择“粗体”并将属性更改为粗体。原始元素被分离,并出现 3 个新元素。我没有测试它,但它可能会调用 insertUpdate() 和 removeUpdate()

    有人知道 Document.setCharacterAttributes 和 Document.setParagraphAttributes 之间的实际区别吗? 有段落和字符属性。字符属性是字体大小、系列、样式、颜色。段落属性是对齐、缩进、行距。 实际上,段落是 char 元素的父元素。

    【讨论】:

    • 我刚刚测试过,在执行高亮显示时,从不调用 insertUpdate() 和 removeUpdate()。我的猜测是,由于高亮是通过设置文本属性来执行的,因此每次调用 Doc.setCharacterAttributes() 时,文档都必须通知文档侦听器,这似乎很耗时。我已经尝试在执行突出显示之前删除文档侦听器,但是由于文档的源是文档侦听器,所以当我删除 DocListener 时,对该文档所做的更改不会更新。
    猜你喜欢
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    相关资源
    最近更新 更多