Search code examples
javaswingloggingjtextareajtextpane

How to log data to a JTextArea (or JTextPane) from a thread that doesn't have a swing component init?


I have a GUI application that process some data, it converts line of text to an object. Each object that is created is shown on a JTextPane ot JTextArea. example:

Line # 1 created 827401830 Line # 2 created 827401831

So the user is inform of the process.

Behind the scene, there's a thread that runs in the background and does all the work. The problem is that one of the fields of this thread has is a JTextArea. and it looks like this:

public class ConsumerThread implements Runnable 
{
    private ArrayBlockingQueue<TicketExchangeLine> queue;
    private JTextArea textArea; 

public ExchConsumerThread(ArrayBlockingQueue<TicketExchangeLine> queue, JTextArea textArea) 
{
    this.queue = queue;
    this.textArea = textArea; 
}

public void run() 
{
    try
    {       
        while (true)
        {               
            // check if end of file from producer POV
            if (queue.peek()!=null && ...)
                break;

            MyObject obj = queue.take();

            try{
                //do the process here
                textArea.append("here comes the output for the user..."+obj.getID);

            }catch(Exception nfe)
            {
                //Oops  
            } 
        }

        textArea.append("\nDone!");

    }catch (InterruptedException e)
    {
        // Oops
    }catch(Exception exp)
    {
        exp.printStackTrace();
    }
}

}

So the code above works fine and does the job but sometimes I'm using this thread not from the GUI and then I'm instantiating a JTextArea for no reason; and even worse, I have to system.out everything to see the process.

Question: how can I log all the 'processed data' to the JTextArea (or sometime JTextPane) without using the Swing components in the thread?

Thanks!


Solution

  • Instead of passing a JTextArea, pass an OutputStream (e.g. a PrintStream) as parameter. This provides enough flexibility:

    • Your thread just writes to the outputstream
    • If you want the output to appear in a JTextArea, you pass an outputstream which will append the output to a JTextArea. The writing to the text area should happen on the EDT, but the outputstream takes care of this. Your thread is unaware of this
    • If you want to pipe the output to the System.out, you just pass the System.out directly as a parameter