我有一个处理一些数据的GUI应用程序,它将文本行转换为对象。创建的每个对象都显示在 JTextPane ot 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();
}
}
}
所以上面的代码工作正常并且可以完成工作,但有时我不是从 GUI 使用这个线程,然后我无缘无故地实例化 JTextArea;更糟糕的是,我必须系统输出所有内容才能看到这个过程。
问题:如何在不使用线程中的 Swing 组件的情况下将所有"已处理的数据"记录到 JTextArea(或有时是 JTextPane)中?
谢谢!
不是传递JTextArea
,而是传递OutputStream
(例如PrintStream
)作为参数。这提供了足够的灵活性:
- 您的线程只是写入输出流
- 如果您希望输出出现在
JTextArea
中,则传递一个输出流,该输出流会将输出附加到JTextArea
。写入文本区域应该在 EDT 上进行,但输出流会处理这个问题。您的线程不知道这一点 - 如果要将输出通过管道传输到
System.out
,只需将System.out
作为参数直接传递
即可
大多数 Swing 图形组件被拆分为图形表示(视图)和显示数据的抽象表示(模型)。 JTextArea
和 JTextPane
是使用 Document
实例作为其模型的图形组件。
因此,您可以引用文档并调用document.insertString
,而不是引用JTextArea
并调用textArea.append
。然后,如果需要实例化 JTextArea,请使用将文档作为参数的 JTextArea 构造函数(或使用其 setDocument
方法)。
此外,Swing 不是线程安全的,每个可能影响 Swing 组件的方法调用都应该发生在 EDT(AWT 的调度线程)中。若要在 EDT 上注入一些代码,请使用 SwingUtilities.invokeLater
。
不确定这是否是你想要实现的目标,但是使用您当前的代码,您可以像这样更改 EDT 上的 JTextArea:
final MyObject obj = queue.take();
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append("here comes the output for the user..." + obj.getID);
}
});
}
您似乎已经找到了答案,但我认为这是解决您问题的优雅而灵活的解决方案:
从不同位置向 JTextArea 发送消息