3
 private void StartActionPerformed(java.awt.event.ActionEvent evt) {

        Queue queue=new Queue();
        int target=Integer.parseInt(Target.getText());
        String path=Path.getText();
        final Producer p=new Producer(queue, target);
        Consumer c=new Consumer(queue);
        p.start();
        c.start();

        while(p.finish !=true)
        {
          Runnable r = new Runnable() {
            public void run() {
              ProgressPrecent.setValue(Producer.ProgressPercent);
            }
          };
          if(EventQueue.isDispatchThread()) {
            r.run();
          }
          else {
            EventQueue.invokeLater(r);
          }
       }
 }

我有两个具有共享队列的类。其中之一是生产者,它生产直到目标另一个消耗这些元素。所有两个都扩展了线程。我想向用户显示进度百分比,但它冻结了我的 GUI,我该怎么办?

4

2 回答 2

6
  • Worker Threads默认情况下从不调用EventDispatchThread,你有问题Concurency in Swing

  • Swing GUI 的所有更新都必须在 EDT 上完成

  • Runnable可能是正确的方式,但ProgressPrecent.setValue(Producer.ProgressPercent);必须包裹在invokeLater

代码

SwingUtilities.invokeLater(new Runnable(){
    public void run(){
        ProgressPrecent.setValue(Producer.ProgressPercent);
    }
}); 
  • 删除对 EDT 的测试,

代码行

if(EventQueue.isDispatchThread()) {
   r.run();
}

Workers Thread默认情况下永远不会调用 EDT,那么无论是否从 EDT 开始,也没有经过测试isDispatchThread()都不会让我感觉

  • 永远不要Thread.sleep(int在里面使用) Swing Listeners,因为也会导致冻结 Swing GUI

  • 我认为您也可以使用SwingWorker 来完成这项工作

于 2012-11-24T18:25:51.177 回答
6

我认为您必须将整个 while 循环放入一个线程中。否则循环将阻止您的 ActionEvent 并因此冻结 UI。

就像是:

new Thread(){
    public void run(){
        while(!p.finish){
           SwingUtilities.invokeLater(new Runnable(){
             public void run(){
               ProgressPrecent.setValue(Producer.ProgressPercent);
             }
           }); 
           try{
              Thread.sleep(100);
           }catch(...){}
        }
    }
}.start();
于 2012-11-24T17:57:14.083 回答