Как регистрировать данные в JTextArea (или JTextPane) из потока, в котором нет компонента Swing?

У меня есть приложение с графическим интерфейсом, которое обрабатывает некоторые данные, оно преобразует строку текста в объект. Каждый созданный объект отображается в JTextPane или JTextArea. пример:

Строка № 1 создана 827401830 Строка № 2 создана 827401831

Таким образом, пользователь информируется о процессе.

За сценой есть поток, который работает в фоновом режиме и выполняет всю работу. Проблема в том, что одним из полей этого потока является JTextArea. и это выглядит так:

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();
    }
}

}

Таким образом, приведенный выше код работает нормально и выполняет свою работу, но иногда я использую этот поток не из графического интерфейса, а затем без причины создаю экземпляр JTextArea; и что еще хуже, мне приходится все выводить из системы, чтобы увидеть процесс.

Вопрос: как я могу регистрировать все «обработанные данные» в JTextArea (или иногда JTextPane) без использования компонентов Swing в потоке?

Спасибо!


person adhg    schedule 04.05.2012    source источник


Ответы (4)


Вместо передачи JTextArea передайте OutputStream (например, PrintStream) в качестве параметра. Это обеспечивает достаточную гибкость:

  • Ваш поток просто пишет в выходной поток
  • Если вы хотите, чтобы вывод отображался в JTextArea, вы передаете поток вывода, который добавит вывод в JTextArea. Запись в текстовую область должна происходить в EDT, но поток вывода позаботится об этом. Ваша ветка об этом не знает
  • Если вы хотите направить вывод на System.out, вы просто передаете System.out напрямую в качестве параметра.
person Robin    schedule 04.05.2012
comment
Вместо OutputStream можно даже использовать Writer, который имеет дело с символами, а не с байтами. - person Jeffrey; 04.05.2012

Большинство графических компонентов Swing разделены на графическое представление (представление) и абстрактное представление отображаемых данных (модель). JTextArea и JTextPane — это графические компоненты, которые используют экземпляр Document в качестве своих моделей.

Таким образом, вместо ссылки на JTextArea и вызова textArea.append вы можете сослаться на документ и вызвать document.insertString. Затем, если вам нужно создать экземпляр JTextArea, используйте конструктор JTextArea, который принимает Document в качестве аргумента (или используйте его метод setDocument).

Кроме того, Swing не является потокобезопасным, и каждый вызов метода, который может повлиять на компонент Swing, должен происходить в EDT (потоке диспетчеризации AWT). Чтобы внедрить код в EDT, используйте SwingUtilities.invokeLater.

person barjak    schedule 04.05.2012

Не уверен, что это то, чего вы пытаетесь достичь, но с вашим текущим кодом вы можете изменить JTextArea на EDT следующим образом:

final MyObject obj = queue.take();
try {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            textArea.append("here comes the output for the user..." + obj.getID);
        }
    });
}
person assylias    schedule 04.05.2012
comment
но вы все еще отправляете textArea в поток. Моя цель - регистрировать события в String (log4j) все, что TextArea может «прослушивать». - person adhg; 04.05.2012
comment
Ах, я не уверен, что что-то подобное существует... Я имею в виду с log4j. Это требование высечено в камне? Если у вас есть глобальный метод статического журнала, этого будет достаточно ?? - person Thihara; 04.05.2012
comment
Эй, чувак, adhg, ты можешь настроить собственный слушатель, но тебе все равно нужно записать его где-то в промежуточном месте, но, как я уже сказал, глобальный статический метод кажется намного чище..... - person Thihara; 04.05.2012

Кажется, вы уже нашли ответ, но я думаю, что это элегантное и гибкое решение вашей проблемы:

Отправка сообщений в JTextArea свинга из разных мест

person grooble    schedule 11.09.2012