0

I have a JTextPane with an extended DefaultStyledDocument. Updating the document takes about 2 minutes. Currently I am breaking it up into steps and updating on the swing thread with InvokeAndWait for each step. I have a progress bar and a cancel button. The cancel button only triggers when there is a break between steps. Each step takes about 10 seconds so I need to wait up to 10 seconds to stop the processing of the document. Is there anyway to make this more responsive? I am displaying a JFrame with the JTextPane in a JScrollPane when it is done. When it is finally rendered the scroll is very responsive and I can view the whole document. I do not want to display the JFrame until the document is updated yet I want to continue to show the progress of the update. Any ideas on how to update the document and have Swing and/or the cancel button more responsive?

====== Edit in response to comments ====== In styled document using the append(text) method - setting styles for each line before appending.

public void append(String text)
{
    append(text, textStyle, paragraphStyle);
}

public void append(String text, Style ts, Style ps)
{
    try
    {
        int start = this.getLength();
        int end = this.getLength()+text.length();
        this.insertString(start, text, ts);
        this.setParagraphAttributes(start, end, ps, true);
    }

    catch (BadLocationException e)
    {
        LOG.log(Level.SEVERE, "Bad location in append", e);
    }
}

======== Edit ======== This is what my document update method looks like.

 public void writeTextOutsideOfSwing(StatusDialog status, float statusPercentage)
  {
    final StringBuilder letter = new StringBuilder();
    final ArrayList<IndexTextEntry>list = new ArrayList<>();
    LOG.log(Level.INFO, "Updating document: {0}", entries.length);
    setText("");
    int step = (int)((status.getMaximum() * statusPercentage) / (double)entries.length);
    for(int j = 0; j < entries.length; j++)
    {
        if(status.cancel) break;
        final int index = j;

        list.add(entries[j]);
        if(list.size() == 100 || index == entries.length -1)
        {
            int first = index - list.size() + 2;
            int last = index + 1;
            status.setStatusBarText("Writing Concordance: Processing " + first + " - " + last + " of " + entries.length);
            try 
            { 
                SwingUtilities.invokeAndWait(()-> 
                {
                    for(int k = 0; k < list.size(); k++)
                    {
                        int i = index-list.size() + k;

                        if(!letter.toString().equals(list.get(k).getSortLetter()))
                        {
                            letter.setLength(0);
                            letter.append(list.get(k).getSortLetter());
                            String title = list.get(k).getSortLetterTitle(letter.toString());
                            appendLetter(title, i == 0);
                        }
                        else if(i > 0)
                        {
                            if(cf.getLineBetweenEntries()) 
                            {
                                clearTextAreaStyles();
                                setFontSize(cf.getLineBetweenEntriesFontSize());
                                append(" \n");
                            }
                        }
                        float indent = appendEntry(0, list.get(k));
                        appendSubEntries(indent, list.get(k));
                    }
                });
            } 
            catch(InterruptedException | InvocationTargetException ex) 
            { LOG.log(Level.SEVERE, "Writing Concorder Interrupted", ex); }
            list.clear();
        }
        status.increment(step);
    }
    LOG.info("Done updating docuemnt");
}

And these methods go with the write method:

 private void appendSubEntries(float indent, IndexTextEntry entry)
 {
    for (IndexTextEntry subEntry : entry.getSubEntries()) 
    {
        float ind = appendEntry(indent, subEntry);
        appendSubEntries(ind, subEntry);
    }
 }

 private float appendEntry(float indent, IndexTextEntry entry)
 {

    setFontFamily(cf.getWordFormat().getFontFamily());
    setFontSize(cf.getWordFormat().getFontSize());
    setFontBold(cf.getWordFormat().getBold());
    setFontItalic(cf.getWordFormat().getItalic());
    switch (cf.getWordFormat().getAlignment()) 
    {
        case TextFormat.ALIGN_CENTER:
            setFontAlignment(EnhancedTextArea.ALIGN_CENTER);
            break;
        case TextFormat.ALIGN_RIGHT:
            setFontAlignment(EnhancedTextArea.ALIGN_RIGHT);
            break;
        default:
            setFontAlignment(EnhancedTextArea.ALIGN_LEFT);
            break;
    }
    float wi = indent + cf.getWordFormat().getIndentJAVA();
    setLeftIndent(wi);
    setFontColor(cf.getWordFormat().getColor());
    append(entry.getConcordance().getTitle());
    append("\n");

    float li = 0;
    for(ConcordanceLine line : entry.getConcordance().getLines())
        li = appendLine(wi, line);

    return li;
}

private float appendLine(float indent, ConcordanceLine line)
{
    setFontFamily(cf.getLineFormat().getFontFamily());
    setFontSize(cf.getLineFormat().getFontSize());
    switch (cf.getLineFormat().getAlignment()) 
    {
        case TextFormat.ALIGN_CENTER:
            setFontAlignment(EnhancedTextArea.ALIGN_CENTER);
            break;
        case TextFormat.ALIGN_RIGHT:
            setFontAlignment(EnhancedTextArea.ALIGN_RIGHT);
            break;
        default:
            setFontAlignment(EnhancedTextArea.ALIGN_LEFT);
            break;
    }
    float li = indent + cf.getLineFormat().getIndentJAVA();
    setLeftIndent(li);
    setFontColor(cf.getLineFormat().getColor());

    setFontBold(cf.getPageBold());
    setFontItalic(cf.getPageItalic());
    append(line.page + " ");
    setFontBold(cf.getLineBold());
    setFontItalic(cf.getLineItalic());
    append(line.lead);
    setFontBold(cf.getWordBold());
    setFontItalic(cf.getWordItalic());
    append(line.word);
    setFontBold(cf.getLineBold());
    setFontItalic(cf.getLineItalic());
    append(line.trail);
    append("\n");

    return li;
}

ALL VARIABLES are resolved before get methods

user1819780
  • 105
  • 11
  • `..with an extended DefaultStyledDocument. Updating the document takes about 2 minutes` - why would anything take that long? We have no idea what you have changed, maybe you should work on that process. `with InvokeAndWait for each step.` - maybe you should be using invokeLater(). I would guess invokeAndWait() would block the EDT while it is waiting for the process to finish. – camickr Oct 23 '18 at 14:55
  • If I use invoke later the process takes just as long an locks up swing. There are many thousands of lines in the document and each line has multiple styles. If you could suggest a way of writing a styled document with many of thousands of lines and multiple styles in each line outside of swing it would be appreciated. – user1819780 Oct 23 '18 at 14:59
  • Create any Strings using a StringBuilder *off* the event thread, and then place the result within the model *on* the event thread. You can use a SwingWorker to do this, especially the publish/process method pair. – Hovercraft Full Of Eels Oct 23 '18 at 15:16
  • String are all created before I start - just using: int start = getLength(); int end = getLength()+text.length(); insertString(start, text, ts) setParagraphAttributes(start, end, ps, true); to append the strings with the style in the document --- If I could speed this up some way? not sure how? – user1819780 Oct 23 '18 at 15:29
  • Still don't know what many thousands means? Still don't know what 10 steps means? Do you process the data 10 times, or try to update in blocks of 10? Still don't know what many styles means? All you show is setting the paragraph attributes. How long does it take do just load the text pane without any formatting? Area you inserting one line at a time or blocks of lines. It doesn't seem like you are doing any parsing of the data so I can't see why inserting the text and setting pargraph attibutes will cause a problem. Give us a better idea of what you are doing. – camickr Oct 23 '18 at 16:04
  • FWIW, I tried to write a "Syntax Document" to highlight java keywords and comments. To read, parse, highlight a 5K line java source file it took 360 ms. – camickr Oct 23 '18 at 16:32
  • Many Thousands - in my test case it is 10251 lines - this can be more or less depending on the document. I Never Said 10 steps - I said each step takes about 10 seconds. In my current test this is about 13 times - each step varies due to the recursion needed to flow through the text --- I insert text until the javax.swing.text.Style changes. then I insert text with the new style. – user1819780 Oct 23 '18 at 16:32
  • My text is more like 200k - never mind - you were talking lines I am talking characters – user1819780 Oct 23 '18 at 16:34
  • My total text was 200k with 5K total lines. So I have the same amount of text but fewer lines. `in my test case it is 10251 lines` - so if you double the line and extrapolate my syntax highlighting then it would be about 7 seconds. `In my current test this is about 13 times - each step varies due to the recursion needed to flow through the text` - so the time taken is in your processing logic, not the logic to add the highlighting. We can't guess what you are doing so we can't make suggestions. – camickr Oct 23 '18 at 16:44
  • I can see that highlight can go fast. I meant about 500k characters - changing font, color, size, paragraph indents etc. - Ideally I would like to do this outside of Swing. – user1819780 Oct 23 '18 at 16:46
  • I just changed my logic to highlight the keyword and increase the font size. The time increased by 10ms. If each step takes 10 seconds then I can see a couple of options: 1) improve the performance of the step 2) breack each step down into processing 500 lines at a time which will give you more opportunities to cancel the step. As has been suggested you would use a SwingWorker and "publish" 500 lines at a time to be processed. See: https://stackoverflow.com/questions/27332210/how-to-handle-multi-line-comments-in-a-live-syntax-highlighter/27338679#27338679 for my old highlighting code. – camickr Oct 23 '18 at 16:59
  • Additional code doesn't help me: 1) I have no idea what you input data is like. 2) the code is not executable. 3) you are using custom classes. 4) I have no idea what all you setXXX() methods do. 5) I have no idea why you invoke the setXXX() method 8 times in one method. In my example code I showed you how to use a `SimpleAttributeSet` to group multiple attributes together. – camickr Oct 23 '18 at 19:44
  • Thanks camickr2 for the help. I took all of the processing code out of the Swing thread and generated an ArrayList of a Sets of text and Styles. (over 35,000 fragments in my test case) Then I processed these sets (fragments) 1000 at a time on the Swing thread. The cancel button is much more responsive and the processing time was cut by about 40%. – user1819780 Oct 23 '18 at 21:58

0 Answers0