2013-10-31 128 views
1

*問題解決了 - 感謝您的所有答案,他們非常有幫助!For循環停止我的揮杆應用程序,直到循環完成

我正在做一個小型的骰子游戲的學校作業,我遇到了這個問題。 我想通過快速循環一些模具圖標來模擬模具的滾動。 這本身並不是導致問題的原因。 如果我直接在JFrame中製作「動畫」,它會正確顯示。我這樣做,是在下面的代碼:

public class Example{ 

     private static ImageIcon die1 = new ImageIcon("terning1.jpg"); 
     private static ImageIcon die2 = new ImageIcon("terning2.jpg"); 
     private static ImageIcon die3 = new ImageIcon("terning3.jpg"); 
     private static ImageIcon die4 = new ImageIcon("terning4.jpg"); 
     private static ImageIcon die5 = new ImageIcon("terning5.jpg"); 
     private static ImageIcon die6 = new ImageIcon("terning6.jpg"); 

     private static JLabel die = new JLabel(die1); 
     private static Random generator = new Random(); 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     frame.add(die); 

     frame.pack(); 
     frame.setVisible(true); 

     for (int i = 0; i < 100; i++) { 
      int x = generator.nextInt(6) + 1; 

      switch(x){ 
       case 1 : die.setIcon(die1); 
        break; 
       case 2 : die.setIcon(die2); 
        break; 
       case 3 : die.setIcon(die3); 
        break; 
       case 4 : die.setIcon(die4); 
        break; 
       case 5 : die.setIcon(die5); 
        break; 
       case 6 : die.setIcon(die6); 
        break; 
      } 

      //Make the loop wait for 50 millis 
      long a, b; 
      a = System.currentTimeMillis(); 
      do { 
       b = System.currentTimeMillis(); 
      } while ((b-a) < 50);   
     } 

    }  
} 

現在工作得很好,但很明顯,它只能當我第一次打開的JFrame。所以我想添加一個按鈕,這使得模具滾動。 但是,如果我添加一個JButton與一個actionlistener,並將for循環放入actionPerformed方法,它停止程序,直到循環完成,並只顯示循環中的最後一個死亡。 例如:

public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     frame.setLayout(new FlowLayout()); 

     frame.add(button); 
     frame.add(die); 

     button.addActionListener(new ButtonListener()); 

     frame.pack(); 
     frame.setVisible(true); 
    } 

    private static class ButtonListener implements ActionListener { 

     public void actionPerformed(ActionEvent event) { 
      for (int i = 0; i < 100; i++) { 
       int x = generator.nextInt(6) + 1; 

       switch (x) { 
        case 1: 
         die.setIcon(die1); 
         break; 
        case 2: 
         die.setIcon(die2); 
         break; 
        case 3: 
         die.setIcon(die3); 
         break; 
        case 4: 
         die.setIcon(die4); 
         break; 
        case 5: 
         die.setIcon(die5); 
         break; 
        case 6: 
         die.setIcon(die6); 
         break; 
       } 

       //Make the loop wait for 50 millis 
       long a, b; 
       a = System.currentTimeMillis(); 
       do { 
        b = System.currentTimeMillis(); 
       } while ((b - a) < 50); 
      } 

有關如何解決此問題的任何提示? 預先感謝!

回答

3

發生什麼事情是,所有Swing事件發生的「事件調度線程」不得不等待您的代碼。不要在事件派發線程上做長時間運行的東西。這是一個着名的反模式。

您應該閱讀Java教程的教程,該教程以http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html開頭,該教程描述了這一點。

兩個小點是不相關的問題的方法:如果你使用ImageIcon的數組變量

  1. 您的代碼會更易於管理,而不是六個獨立的變量。
  2. 您可以使用Thread類的sleep方法,而不是您正在使用的「繁忙睡眠」。
1

您的用戶界面被鎖定,因爲所有內容都在同一個線程中,因此必須等到for循環完成執行。您需要在單獨的線程中運行您的邏輯。

0

您在EDT運行您的actionPerformed(ActionEvent event)方法,因爲您無法更新UI。要從代碼更新UI,請嘗試使用SwingWorker,它可以在後臺進程運行時更新UI。你可以在互聯網上找到很多它的例子。

或者您可以嘗試使用Executors作爲後臺進程並更新EDT中的UI。

0

Swing的事件處理代碼在EDT(甚至是調度線程)中運行。 ActionEvent也不例外。 EDT內部不能執行任何長時間運行的任務。把你的骰子滾動循環一個新的線程中:

new Thread(){ 
    public void run(){ 
     // your dice rolling code 
    } 
    }.start(); 

,然後更新使用SwingUtilities.invokdeLater()的GUI。

注意:除了使用switch-case進行條件處理,您可以使用ImageIcon的數組,並使用隨機生成的索引訪問它。

int x = generator.nextInt(6) + 1; 
die.setIcon(imageIconArr[x]); // array of image icon 

See this answer for details.