2010-04-26 26 views
1

我有一些需要几分钟处理的代码,它必须连接到Web上的每个字符串在一个长数组中,每个字符串都是一个url。我想让它每次连接的时候都应该刷新jtextarea,以便用户不会盯着一个看起来冻结了20分钟的空白页面。或者需要很长时间。这里的东西我想和没有工作的例子:实时输出到jTextArea

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

回答

10

问题是你需要异步执行计算。您应该创建一个执行计算的后台线程,然后使用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(); 

编辑
据指出,JTextArea中的附加功能实际上是线程安全的(不像大多数Swing功能)。因此,对于这种情况,不需要通过invokeLater进行更新。但是,你还是应该做你在后台线程处理,以使图形用户界面进行更新,因此代码:

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

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

+0

谢谢,我已经掌握了一切,但它告诉我需要做最后的决定,所以应该是(最终String s:mylinks)呢? – 2010-04-26 02:14:36

+0

对于上面的例子,myLinks需要是最终的。 – 2010-04-26 02:16:08

+0

但是如果你在线程之外有for-loop,那么你需要做最后的决定(创建最终的fs = s;并使用fs)。 – 2010-04-26 02:16:49

0

摆动/ AWT是单线程库,所以一旦一个部件所示,只是改变它的外形将无法正常工作。您需要在GUI线程上更改组件,而不是从线程中更改组件。要在

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

也想限制你的GUI线程上怎样做才能避免成为低迷的GUI做这个包装与SwingUtilities.invokeLater更新组件的任何代码......,所以,如果checkFileStatus是耗时,在run方法之外执行它并将结果存储在最终的局部变量中,并只需在run()代码中访问该变量即可。

+0

好的,谢谢,我现在就试试这个:-) – 2010-04-26 02:10:25

+0

SwingUtils是什么包? – 2010-04-26 02:11:27

+0

抱歉,javax.swing.SwingUtilities – MeBigFatGuy 2010-04-26 02:14:33

1

您需要调查Swing中的线程及其relationship to GUI updates。任何影响或使用Swing中GUI组件的事情都必须在称为Event Dispatch Thread (EDT)的特殊线程上完成。

如果你的代码片断,如果它冻结的GUI,我想它是在EDT运行。在EDT上执行长时间运行操作会导致GUI无响应,因为在长时间运行的进程正在使用线程时无法进行进一步的更新。

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

+0

谢谢。上面的答案使我能够立即开始工作,但我认为从长远来看,我应该研究这一点,并理解它是如何工作的。 – 2010-04-26 02:24:52