2010-11-19 84 views
5

我有这个在EDT中被调用的ActionListener。我的plot()函数在计算量上很大,很容易花费五秒钟。它使GUI按预期挂起。我添加了SwingUtilities.invokeLater的代码,它仍然挂起。现在我不能为我的升沉计算产生一个单独的线程来响应GUI吗?即使使用SwingUtilities.invokeLater后,为什么我的GUI仍然挂起?

final ActionListener applyListener = new ActionListener() 
     { 
      @CommitingFunction 
      public void actionPerformed(ActionEvent arg0) 
      { 
       /*Don't do plotting in the EDT :)*/ 
       SwingUtilities.invokeLater(new Runnable() 
       { 
        public void run() 
        { 
         plot(); 
        } 
       }); 
      } 
     }; 

回答

15

根本没有。 InvokeLater不会生成新线程。 invokeLater exists to tell Swing explicitly "use the Event Dispatching Thread for this, but not right now". invoke和invokeLater的存在让你可以只对其他线程进行事件派发线程安全的操作,而不是在这些线程上执行它们,而是告诉EDT来执行操作。

您的ActionListener将运行得非常快,将Runnable引发到Swing的事件派发队列中。然后,当它达到那么远时,将需要五秒钟来运行plot()。

唯一的解决方法是重构plot()。使用SwingWorker(或类似的多线程策略,但SwingWorker可能是最好的),以将plot()的逻辑实际移动到不同的线程上。该线程不能安全地绘制任何东西,因为它不是Swing事件派发线程,所以它的所有绘制操作都需要通过invokeLater()来执行。出于效率原因,您应该尝试使用一次invokeLater(),一次执行所有绘图操作,并使用计算结果中存储的结果。

+1

所以做我想要做的情节()的代码运行在扩展一个类SwingWorker,然后在doInBackground()函数中运行这个计算繁重的代码,然后使用done()函数来刷新我的显示?在计算发生时,我的GUI仍然处于活动状态? – smuggledPancakes 2010-11-19 18:03:04

+0

@ user464095:是的,确切地说。 – ColinD 2010-11-19 18:06:24

+1

宾果。这就是SwingWorker的功能和用途。 – 2010-11-19 18:07:09

1

invokeLater将任务添加到GUI工作队列。它将在所有其他任务执行后被调用,但它仍然使用GUI线程。

我建议你看看使用ExecutorService。

正如@Adam所说,它所做的任何实际绘图都需要通过invokeLater完成。

1

您不会显示plot()函数内部的内容,但您应该在而不是中放置任何绘画。在新线程中计算任何你想要的东西,然后在EDT中进行绘画。要做到这一点,最好使用SwingWorker

3

你正在做的和你认为的相反。除了在EDT之外运行你的计算线程,你明确地称它为它在之内!

SwingUtilities.invokeLater()在稍后的EDT中排队调用runnable!您想用SwingWorker代替。

1

以下是我为我公司的应用程序所做的工作,由于法律原因,这是一些伪代码,但问题是,如果屏幕无响应,它将重新启动GUI。每当您使用SwingUtilities启动EDT时,在同一个初始化块中创建两个观察器线程。一个线程只会使用Swing实用程序在EDT线程上执行一个操作。另一个线程将监视第一个线程,看看是否感觉第一个线程有响应。如果第一个线程可以执行一个非常简单的命令,它只会承认响应。

集isEDTCheck为true在正常运行方式时,假在调试模式(否则你会不断地得到重启。

if (isEDTCheck) { 
     new Thread("EDTHeartbeat") { 
      @Override 
      public void run() { 
       Runnable thisThingYouDo = new Runnable() { 
        public void run() { 
         int x = 0; 
        } 
       }; 
       while (true) { 
        // first thread says we are waiting, aka bad state 
        edtwait=true; 
        try { 
         javax.swing.SwingUtilities.invokeAndWait(thisThingYouDo); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        // first thread says we are not waiting, good state 
        edtwait=false; 
        try { 
         Thread.sleep(5000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      } 
     }.start(); 

     new Thread("EDTValidator") { 
      @Override 
      public void run() { 
       while (true) { 
        // is first thread in bad state? 
        if (edtwait) { 
         try { 
          Thread.sleep(3000); 
          // after 3 seconds are we still in bad state? if so, get rid of initial frame, pop up a dialog box in AWT that does no commands 
          if (edtwait) { 
           mainFrame.setVisible(false); 
           new Dialog(); 
          } catch (InterruptedException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
         } 
        } 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      } 
     }.start(); 
    } 


    public class Dialog extends Frame { 
    private static final int WIDTH = 400; 
    private static final int HEIGHT = 300; 
    Frame f = null; 
    public Dialog() { 
     f = this; 
     hasSomethingBeenEntered=false; 
     this.setTitle("APP PROBLEM DETECTED"); 
     this.setSize(WIDTH, HEIGHT); 
     this.setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - myapp.width, 0); 
     Panel p1 = new Panel() { 
      @Override 
      public void paint(final Graphics g) { 
       int left = Dialog.WIDTH/2 - 45; // don't use WIDTH shadowed by Panel class 
       int top = Dialog.HEIGHT/2 - 20; // same as above 
       g.drawString("APP HAS DETECTED A PROBLEM", left, top); 
      } 
     }; 
     this.add("Center", p1); 

     this.setAlwaysOnTop(true); 
       TextArea tb = new TextArea("APP HAS DETECTED A MAJOR PROBLEM\nIT WILL NOW RESTART IN 5 SECONDS"); 
     this.add(tb); 
     this.setVisible(true); 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     restartApp(); 

    } 

    private void restartApp() { 
      Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"cd C:\\Progra~1\\Common~1 && C:\\Progra~1\\Common~1\\MyAppDir\\myjavaapp.jar\""); 
      System.exit(0); 
     } 
相关问题