2

I have a very long string which I get from a book. I display it in a JTextArea by using the setText() method. It freezes the UI and takes a lot of time. How do I get around that?

Here is as SSCCE:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class SSCCE extends JFrame {

    JTextArea textArea;

    public SSCCE() {
        String text = buildLongString(400000);
        textArea = new JTextArea();
        textArea.setText(text);
        textArea.setLineWrap(true);
        add(new JScrollPane(textArea));

        setSize(400, 350);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    private String buildLongString(int length) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append("x");
        }
        return builder.toString();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new SSCCE();
            }
        });
    }

}
usama8800
  • 893
  • 3
  • 10
  • 20
  • 2
    You are really dumping 400,000 characters of text onto the unfortunate user? What is the point of all this? – Andrew Thompson May 30 '14 at 09:33
  • I donot see any code modification required. – Arijit May 30 '14 at 09:35
  • 3
    Interestingly it's the `textArea.setLineWrap(true);` (indirectly not on call) that takes all the time. Putting the text there is actually fast. BAs an example, concatenating "x", if you concatenate "x\n" it becomes really fast. – DSquare May 30 '14 at 09:36
  • 1
    @DSquare shows the correct thing to do: [profile](http://stackoverflow.com/q/2064427/230513). This [approach](http://stackoverflow.com/a/23924757/230513) may help. – trashgod May 30 '14 at 09:37
  • 1. (1st. aid) I didn't see that you works with Caret, set possition for Caret to 0, to the start of Document (safe about 50-70 pct), 2. JTextComponents arent designated to nest bunch of Chars, but JTextPane or JEditorPane can better to manage larger Document, 3. resize of JTextArea should be awfull – mKorbel May 30 '14 at 09:48
  • @DSquare excelent catch +++, but resize is still " brrrrrrrr" – mKorbel May 30 '14 at 09:50
  • @mKorbel Where am I resizing the JTextArea? – usama8800 May 30 '14 at 09:55
  • @usama8800 maybe you didn't, but anyone who has mouse or keyboard can do that – mKorbel May 30 '14 at 11:10

2 Answers2

5

Creating a DefaultStyledDocument in a separate thread from constructing the GUI seems to be the fastest way to create a huge text area. A DefaultStyledDocument is thread safe.

Here's the code I used to test the DefaultStyledDocument. I created text with spaces so that the Swing code to line wrap had a chance to work.

package com.ggl.testing;

import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;

public class HugeTextArea implements Runnable {

    private DefaultStyledDocument   document;

    private JFrame                  frame;

    private JTextArea               textArea;

    public HugeTextArea() {
        this.document = new DefaultStyledDocument();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                buildLongString(400000);
            }
        };
        new Thread(runnable).start();
    }

    @Override
    public void run() {
        frame = new JFrame();
        frame.setTitle("Huge Text");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        textArea = new JTextArea(document);
        textArea.setLineWrap(true);
        frame.add(new JScrollPane(textArea));

        frame.setSize(400, 350);
        frame.setLocationRelativeTo(null);

        frame.setVisible(true);
    }

    private void buildLongString(int length) {
        Random random = new Random();
        String[] chars = { "s", "t", "a", "y", " " };
        for (int i = 0; i < length; i++) {
            try {
                document.insertString(document.getLength(),
                        chars[random.nextInt(chars.length)],
                        null);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new HugeTextArea());
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
0

I called the method setText(..) from inside invokeLater(...) block, performance was improved a lot

EventQueue.invokeLater(new Runnable()
{
    public void run()
    {
        txt.setText(content);
    }
});
Adir Dayan
  • 1,308
  • 13
  • 21