1

我有一些代码需要几分钟才能处理,它必须为长数组中的每个字符串连接到网络,每个字符串都是一个 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);
        }
4

3 回答 3

10

问题是您需要异步执行计算。您应该创建一个执行计算的后台线程,然后使用SwingUtilities.invokeLater更新 JTextArea。

final ArrayList<String> myLinks = //...
(新线程()
{
    公共无效运行(){
        对于(字符串 s:myLinks){
            尝试{
               最终字符串结果 = LinkChecker.checkFileStatus(s) + "\n";
               SwingUtilities.invokeLater(new Runnable(){
                    公共无效运行(){    
                      jtextArea2.append(结果);
                    }
                });
             }catch(IOException 错误){
                // 处理错误
             }
        }
    }
})。开始();

编辑
有人指出,JTextArea 的 append 函数实际上是线程安全的(与大多数 Swing 函数不同)。因此,对于这种特殊情况,无需通过 invokeLater 对其进行更新。但是,您仍然应该在后台线程中进行处理以允许 GUI 更新,因此代码是:

final ArrayList<String> myLinks = //...
(新线程()
{
    公共无效运行(){
        对于(字符串 s:myLinks){
            尝试{
               jtextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
             }catch(IOException 错误){
                // 处理错误
             }
        }
    }
})。开始();

但是,对于修改 Swing 对象的几乎所有其他操作,您将需要使用 invokeLater(以确保修改发生在 GUI 线程中),因为几乎所有 Swing 函数都不是线程安全的。

于 2010-04-26T02:10:21.827 回答
1

您需要调查线程及其与Swing中的 GUI 更新的关系。在 Swing 中影响或使用 GUI 组件的任何事情都必须在称为事件调度线程 (EDT)的特殊线程上完成。

如果您的代码片段冻结了 GUI,我想它正在 EDT 中运行。在 EDT 上执行长时间运行的操作将使 GUI 无响应,因为在长时间运行的进程使用线程时无法进行进一步的更新。

有一个名为的帮助SwingWorker程序类允许您将长时间运行的计算卸载到后台线程,然后在完成时对 GUI 线程进行更新。在SwingWorkerGUI 线程和后台线程之间切换上下文。您还可以显示进度条,让用户知道长时间运行的进程的状态,以便他们知道您的应用程序没有挂起。

于 2010-04-26T02:14:26.480 回答
0

swing/awt 是一个单线程库,因此一旦显示组件,仅更改其外观将无法正常工作。您需要更改 GUI 线程上的组​​件,而不是您的线程。为此,使用 SwingUtilities.invokeLater... 包装任何更新组件的代码,如

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
    }
});

您还想限制您在 gui 线程上执行的操作以避免 gui 变得迟缓,因此如果 checkFileStatus 很耗时,请在 run 方法之外执行它并将结果存储在最终的局部变量中,然后只需访问运行()代码。

于 2010-04-26T02:09:09.417 回答