我什么时候应该使用javax.swing.SwingUtilities.invokeLater()?

时间:2014-09-21 00:16:57

标签: java swing event-dispatch-thread jprogressbar

我有一个使用JProgressBar的GUI。 GUI具有JBUTTONs,可以调用以下代码:

public void updateProgressBar(int x) {
    System.out.println(javax.swing.SwingUtilities.isEventDispatchThread());
    healthBar.setValue(x);
}

但我也做了一个循环,定期调用相同的方法。

public class Loop implements Runnable {
    public void run() {
        while (true) { Thread.sleep(2000); updateProgressBar(0); }
    }
}

现在,据我所知,任何改变我的GUI都需要从EDT执行。 JProgressBar.setValue(x)更改了我的GUI,当从Loop类调用它时,isEventDispatchThread检查失败,这一切都很好,很明显。然而,我无法理解的是,如果这也意味着我应该使用SwingUtilities.invokeLater() setValue()。我担心的是,因为我不知道setValue()实际上是如何工作的,所以我不必要地使用invokeLater()甚至在使用它时破坏了一些东西。

我不知道如何更好地问我的问题:如果我知道改变我的GUI的方法没有从EDT调用,那么我是否也知道我必须使用invokeLater()

1 个答案:

答案 0 :(得分:5)

一种可能的解决方案是创建一个检查线程是否为EDT的方法,如果是,则直接更新该条,否则在EDT上排队:

public void updateProgressBar(int value) {
   progressBar.setValue(value);
}

public void safeUpdateProgressBar(final int value) {
   if (SwingUtilities.isEventDispatchThread()) {
      updateProgressBar(value);
   } else {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            updateProgressBar(value);
         }
      });
   }
}

但是有很多方法可以给这只猫留下光泽。例如,

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

public class ProgExample extends JPanel {
   private JProgressBar progressBar = new JProgressBar(0, 100);

   public ProgExample() {
      progressBar.setBorderPainted(true);
      progressBar.setStringPainted(true);
      add(progressBar);
      add(new JButton(new ProgressAction1("Action 1", KeyEvent.VK_1, this)));
      add(new JButton(new ProgressAction2("Action 2", KeyEvent.VK_2, this)));
      add(new JButton(new ProgressAction3("Action 3", KeyEvent.VK_3, this)));
   }

   public void updateProgressBar(int value) {
      progressBar.setValue(value);
   }

   public void safeUpdateProgressBar(final int value) {
      if (SwingUtilities.isEventDispatchThread()) {
         updateProgressBar(value);
      } else {
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               updateProgressBar(value);
            }
         });
      }
   }

   private static void createAndShowGui() {
      ProgExample mainPanel = new ProgExample();

      JFrame frame = new JFrame("ProgExample");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class ProgressAction1 extends AbstractAction {
   private static final int MAX_VALUE = 100;
   protected static final long SLEEP_TIME = 100;
   protected static final int STEP = 2;
   private ProgExample gui;

   public ProgressAction1(String name, int mnemonic, ProgExample gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      new Thread(new Runnable() {
         private int value = 0;
         @Override
         public void run() {
            while (value <= MAX_VALUE) {
               gui.safeUpdateProgressBar(value);
               value += STEP;
               try {
                  Thread.sleep(SLEEP_TIME);
               } catch (InterruptedException e) {}
            }
            gui.safeUpdateProgressBar(MAX_VALUE);
         }
      }).start();
   }
}

class ProgressAction2 extends AbstractAction {
   private static final int MAX_VALUE = 100;
   protected static final long SLEEP_TIME = 100;
   protected static final int STEP = 2;
   private ProgExample gui;

   public ProgressAction2(String name, int mnemonic, ProgExample gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
         private int value = 0;

         @Override
         protected Void doInBackground() throws Exception {
            while (value <= MAX_VALUE) {
               setProgress(value);
               value += STEP;
               try {
                  Thread.sleep(SLEEP_TIME);
               } catch (InterruptedException e) {}
            }
            setProgress(MAX_VALUE);
            return null;
         }
      };
      worker.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if ("progress".equals(pcEvt.getPropertyName())) {
               gui.updateProgressBar(worker.getProgress());
            }
         }
      });
      worker.execute();
   }
}

class ProgressAction3 extends AbstractAction {
   private static final int MAX_VALUE = 100;
   protected static final int SLEEP_TIME = 100;
   protected static final int STEP = 2;
   private ProgExample gui;

   public ProgressAction3(String name, int mnemonic, ProgExample gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      new Timer(SLEEP_TIME, new ActionListener() {
         int value = 0;

         @Override
         public void actionPerformed(ActionEvent e) {
            if (value <= MAX_VALUE) {
               gui.updateProgressBar(value);
               value += STEP;
            } else {
               gui.updateProgressBar(MAX_VALUE);
               ((Timer) e.getSource()).stop();
            }

         }
      }).start();
   }
}