2013-03-01 50 views
0

我有一個在EDT內執行的方法。這件事情是這樣的:EDT擺動問題

myMethod() 
{ 
    System.out.prinln(SwingUtilities.isEventDispatchThread()); 

    for (int i = 0; i < 10; i++) 
    { 
    Thread.sleep(3000); 
    someJPanel.remove(otherJPanel); 
    } 
} 

我希望發生: 十JPanels會從他們的父母一一拆下,用在每次取出之間有三個秒鐘間隔...

實際發生的事情: 所有10個元素一次被刪除後,所有內容都被凍結了30秒。

控制檯中的行始終爲真(SwingUtilities.isEventDispatchThread())。

由於我在美國東部時間所做的一切,爲什麼這些變化不是即時的?它爲什麼要等待該方法首先達到目的?

我應該如何修改我的代碼以實現三秒延遲inbetween清除?

+0

要刪除的組件,但是從UI實際去除稍微幹了以後再 – 2013-03-01 02:07:42

+0

我完全意識到這一點。我該如何讓它瞬間完成? – Karlovsky120 2013-03-01 02:08:24

+0

您需要從EDT之外延遲。您的睡眠(3000)正在star the正常的Swing UI,包括實際移除組件。查看MadProgrammer的答案。 – 2013-03-01 02:10:30

回答

7

Swing使用單線程來分派事件並處理重繪請求。無論何時您阻止此線程,您都會停止EDT處理這些重繪請求,使UI看起來像是「停止」。

而是使用類似javax.swing.Timer的東西來插入延遲並執行操作。這將在EDT內執行動作,但會在後臺線程中等待。

有一個讀通過The Event Dispatching Thread瞭解詳細信息...

更新與定時器實例

public class SlowDecline { 

    public static void main(String[] args) { 
     new SlowDecline(); 
    } 
    private TestPane last; 

    public SlowDecline() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       TestPane parent = new TestPane(Color.RED); 
       TestPane tp = add(parent, Color.BLUE); 
       tp = add(tp, Color.GREEN); 
       tp = add(tp, Color.CYAN); 
       tp = add(tp, Color.LIGHT_GRAY); 
       tp = add(tp, Color.MAGENTA); 
       tp = add(tp, Color.ORANGE); 
       tp = add(tp, Color.PINK); 

       last = tp; 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(parent); 
       frame.setSize(200, 200); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

       Timer timer = new Timer(1000, new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         if (last != null) { 
          Container parent = last.getParent(); 
          if (parent != null) { 
           parent.remove(last); 
           parent.repaint(); 
           if (parent instanceof TestPane) { 
            last = (TestPane) parent; 
           } 
          } else { 
           last = null; 
          } 
         } else { 
          (((Timer)e.getSource())).stop(); 
         } 
        } 
       }); 
       timer.setRepeats(true); 
       timer.setCoalesce(true); 
       timer.start(); 
      } 
     }); 
    } 

    public TestPane add(TestPane parent, Color color) { 

     TestPane child = new TestPane(color); 
     parent.add(child); 
     return child; 
    } 

    public class TestPane extends JPanel { 

     public TestPane(Color background) { 
      setLayout(new BorderLayout()); 
      setBorder(new EmptyBorder(10, 10, 10, 10)); 
      setBackground(background); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(50, 50); 
     } 
    } 
} 
4

這是因爲UI線程負責繪畫的屏幕,以及處理事件。當你讓UI線程進入睡眠狀態時,不會再出現任何繪畫或事件處理。當線程恢復繪製時,所有面板都已被移除。

該網址在how to handle threading with Swing上非常全面。

您最好創建一個移除面板的線程。

(未經測試)

Thread t = new Thread() { 
    @Override 
    public void run() { // override the run() for the running behaviors 
    for (int i = 0; i < 10; i++) 
    { 
     Thread.sleep(3000); 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
      someJPanel.remove(...); 
      }); 
    } 
    } 
}; 
t.start(); // call back run() 
+0

所以實際的去除不是從EDT執行的,只是視覺? – Karlovsky120 2013-03-01 02:15:36

+2

InvokeLater將導致面板在EDT上被刪除。上面的代碼示例避免了在EDT上睡覺,所以您不會遇到UI凍結。 – 2013-03-01 02:17:21