java 实时输出到 jTextArea
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2710712/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Output to jTextArea in realtime
提问by Robert Cardona
I have some code which takes a few minutes to process, it has to connect to the web for each string in a long array, each string is a url. I want to make it so that everytime it connects, it should refresh the jtextarea so that the user is not staring into a blank page that looks frozen for 20 min. or however long it takes. here is an example of something i tried and didnt work:
我有一些代码需要几分钟来处理,它必须为长数组中的每个字符串连接到网络,每个字符串都是一个 url。我想让它每次连接时都应该刷新 jtextarea,这样用户就不会盯着一个看起来冻结了 20 分钟的空白页面。或无论需要多长时间。这是我尝试过但没有奏效的例子:
try {
ArrayList<String> myLinks = LinkParser.getmyLinksArray(jTextArea1.getText());
for (String s : myLinks) {
jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}
} catch (IOException ex) {
JOptionPane.showMessageDialog(jTextArea1, "Parsing Error", "Parsing Error", JOptionPane.ERROR_MESSAGE);
Logger.getLogger(MYView.class.getName()).log(Level.SEVERE, null, ex);
}
回答by Michael Aaron Safyan
The problem is that you need to perform the computation asynchronously. You should create a background thread that performs the computation, and then use SwingUtilities.invokeLaterto update the JTextArea.
问题是您需要异步执行计算。您应该创建一个执行计算的后台线程,然后使用SwingUtilities.invokeLater更新 JTextArea。
final ArrayList<String> myLinks = //...
(new Thread()
{
public void run(){
for (String s : myLinks) {
try{
final String result = LinkChecker.checkFileStatus(s) + "\n";
SwingUtilities.invokeLater(new Runnable(){
public void run(){
jtextArea2.append(result);
}
});
}catch(IOException error){
// handle error
}
}
}
}).start();
Edit
It has been pointed out that JTextArea's append function actually is thread safe (unlike most Swing functions). Therefore, for this particular, case it is not necessary to update it via invokeLater. However, you should still do you processing in a background thread so as to allow the GUI to update, so the code is:
编辑
已经指出 JTextArea 的 append 函数实际上是线程安全的(与大多数 Swing 函数不同)。因此,对于这种特殊情况,不需要通过 invokeLater 更新它。但是,您仍然应该在后台线程中进行处理以允许 GUI 更新,因此代码为:
final ArrayList<String> myLinks = //...
(new Thread()
{
public void run(){
for (String s : myLinks) {
try{
jtextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}catch(IOException error){
// handle error
}
}
}
}).start();
However, for pretty much any other operation that modifies a Swing object, you will need to use invokeLater (to ensure the modification occurs in the GUI thread), since almost all the Swing functions aren't thread safe.
但是,对于修改 Swing 对象的几乎所有其他操作,您将需要使用 invokeLater(以确保在 GUI 线程中进行修改),因为几乎所有 Swing 函数都不是线程安全的。
回答by Ash
You need to investigate threading and its relationship to GUI updatesin Swing. Anything that affects or makes use of GUI components in Swing must done on a special thread called the Event Dispatch Thread (EDT).
您需要研究线程及其与Swing 中GUI 更新的关系。在 Swing 中影响或使用 GUI 组件的任何事情都必须在称为事件调度线程 (EDT)的特殊线程上完成。
If your code snippet, if it's freezing the GUI, I imagine that it is being run in the EDT. Performing a long-running action on the EDT will make the GUI unresponsive, because no further updates can be done while your long-running process is using the thread.
如果你的代码片段,如果它冻结了 GUI,我想它是在 EDT 中运行的。在 EDT 上执行长时间运行的操作将使 GUI 无响应,因为在长时间运行的进程正在使用线程时无法进行进一步的更新。
There is a helper class called SwingWorkerthat allows you to offload long-running computations to a background thread, and then make updates to the GUI thread when it is complete. The SwingWorkerlooks after the context switches between the GUI thread and the background thread. You can also display progress bars to let the user know the state of the long-running process, so they know your application hasn't hung.
有一个名为的帮助程序类SwingWorker,它允许您将长时间运行的计算卸载到后台线程,然后在完成后更新 GUI 线程。在SwingWorker上下文后看起来GUI线程和后台线程之间进行切换。您还可以显示进度条,让用户知道长时间运行的进程的状态,让他们知道您的应用程序没有挂起。
回答by MeBigFatGuy
swing/awt is a single threaded library, so once a component is shown, just changing it's appearance won't work correctly. You need to change the component on the GUI Thread, not from your thread. To do this wrap any code that updates a component with SwingUtilities.invokeLater... as in
Swing/awt 是一个单线程库,所以一旦显示了一个组件,仅仅改变它的外观将无法正常工作。您需要更改 GUI 线程上的组件,而不是您的线程。为此,请使用 SwingUtilities.invokeLater... 包装任何更新组件的代码,如
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}
});
also you want to limit what you do on the gui thread to avoid the gui from becoming sluggish, so if checkFileStatus is time consuming, execute it outside the run method and store the result in a final local variable, and just access the variable in the run() code.
你还想限制你在 gui 线程上所做的事情,以避免 gui 变得迟钝,所以如果 checkFileStatus 很耗时,请在 run 方法之外执行它并将结果存储在一个最终的局部变量中,并且只需访问变量中的运行()代码。

