2012-03-21 34 views
3

我正在用java製作一個簡單的棋盤遊戲,我想在這裏製作一個擲骰子的動畫。所以我閃骰子的圖片是這樣的:僅在Java Swing中重繪後觸發事件?

public Timer roll_dice = new Timer(50, this); 
... 
public void actionPerformed(ActionEvent evt) { 
     if(roll_dice.getDelay() > 500){ 
      roll_dice.setDelay(50); 
      roll_dice.stop(); 
      movePiece(); 
     }else{ 
      roll_dice.setDelay(roll_dice.getDelay() + 50); 
      dice_panel.repaint(0); 
     } 
    } 
} 

movePiece(){ 
    //do some more painting 
} 

所以模具會這麼顯示的隨機數了幾遍,然後對一些緩慢沉降。完成之後,我想打電話給movePiece()方法。然而,實際上,重新繪製是零星發​​生的,並且將所有東西都擰緊,以便在骰子滾動實際完成動畫之前調用movePiece()

有沒有人有任何想法我只能在最後的重繪發生後才能調用movePiece?

+1

您應該避免讓程序邏輯依賴於繪畫,因爲您無法完全控制何時甚至是否出現繪畫。爲什麼不簡單地將滾動的骰子圖像放入ImageIcons中,而是在程序啓動時,然後在Swing Timer中,交換JLabel中的圖標,而不是重繪圖像並調用repaint()。然後停止你的計時器,當延遲時間足夠長時,如果阻止,移動你的作品。 – 2012-03-21 16:26:44

回答

1

所以模具會這麼顯示的隨機數了幾遍,然後對一些緩慢沉降。完成之後,我想調用movePiece()方法。但是,實際上,重繪會偶爾出現,並將所有東西都擰緊,以便在骰子滾動實際完成動畫之前調用movePiece()。

這裏什麼讓我擔心的是,爲什麼你的畫是零星發生 - 它根本不應該這樣做,也許是你需要解決什麼。我想知道,如果每次進行繪圖或其他原因導致繪圖放慢時,是否從文件中讀取圖像。如果您需要更多關於此問題的幫助,那麼您必須向我們提供有關您如何進行繪畫的更多信息。無論如何,您應該避免讓程序邏輯依賴繪畫,因爲您無法完全控制何時或甚至是否出現繪畫。

與其重繪圖像並調用repaint(),爲什麼不簡單地將滾動的骰子圖像放入程序啓動的ImageIcons中,然後在Swing Timer中交換JLabel中的圖標?然後停止你的計時器,當延遲時間足夠長時,如果阻止,移動你的作品。

因此,假設您有多個骰子,每個骰子都可以通過JLabel顯示,該JLabel保存在名爲diceLabels的JLabel數組中,並且ImageIcons可以保存在名爲diceIcons的數組中。然後,你可以這樣做:

public void actionPerformed(ActionEvent e) { 
    if (roll_dice.getDelay() > 500) { 
     roll_dice.setDelay(50); 
     roll_dice.stop(); 
     movePiece(); // I like this -- this shouldn't change 
    } else { 
     roll_dice.setDelay(roll_dice.getDelay() + 50); 
     // dice_panel.repaint(0); 
     for (JLabel dieLabel : diceLabels) { 
      int randomIndex = random.nextInt(diceIcons.length); 
      dieLabel.setIcon(diceIcons[randomIndex]); 
     } 
    } 
    } 

我喜歡你的邏輯,當你調用movePiece()上,我認爲這應該保持不變。

+0

謝謝,這讓我的生活變得更加輕鬆。 – wbarksdale 2012-03-21 18:13:09

+0

@weezybizzle:你很受歡迎。 – 2012-03-21 18:14:55

0

您可以在另一個線程中調用滾動並將當前線程加入()到滾動線程中。這樣主代碼就會等待,直到卷線程停止(完成滾動)。

public void actionPerformed(ActionEvent evt) { 
    if(roll_dice.getDelay() > 500){ 
     Thread rollerThread = new RollerThread(); 
     rollerThread.start(); 
     rollerThread.join(); 
     movePiece(); 
    } 
    else{ 
     roll_dice.setDelay(roll_dice.getDelay() + 50); 
     dice_panel.repaint(0); 
    } 
} 

private RollerThread extends Thread 
{ 
    public void run(){ 
     roll_dice.setDelay(50); 
     roll_dice.stop(); 
    } 
} 

然而,這可能不是與EDT工作 - 因爲重繪應該計劃到隊列中。也許你可以使用shedule事件的SwingUtilities.invokeAndWait()

public void actionPerformed(ActionEvent evt) { 
    Thread thread = new Thread(){ 
     public void run(){ 
      if(roll_dice.getDelay() > 500){ 
       SwingUtilities.invokeAndWait(new Runnable(){ 
        public void run(){ 
         roll_dice.setDelay(50); 
         roll_dice.stop(); 
        } 
       }); 
       movePiece(); 
      } 
      else{ 
       roll_dice.setDelay(roll_dice.getDelay() + 50); 
       dice_panel.repaint(0); 
      } 
     } 
    }; 
    thread.start(); 
} 
+0

我不確定這會解決問題,因爲重新繪製是零星調用的。這不就是把同樣的問題移到另一個線程嗎? – wbarksdale 2012-03-21 15:49:17

+0

@ weezybizzle查看編輯 – 2012-03-21 15:51:27

0

做任何事情的變化,如果你把一個SwingUtilities.invokeLater(Runnable);該呼叫movePiece();

if(roll_dice.getDelay() > 500){ 
    roll_dice.setDelay(50); 
    roll_dice.stop(); 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { movePiece(); } 
    }); 
} 
...