2016-11-24 91 views
0

我試圖做一個JButton 發起解決迷宮的動畫。我有一個遞歸的,深度優先的搜索功能,可以找到路徑,但是會逐漸爲其着色(使用Thread.sleep())。代碼完美工作。我的問題是有一個按鈕啓動這個動畫。創建一個ActionListener,逐步更新JPanel

當我將函數添加到JButton的actionPerformed中時,解決方案只會在完成後纔會出現(不是一步一步地)。我得知這是因爲動作監聽器是單線程或類似的東西,所以我試圖使用Swing Timer。我只是簡單地創建了一個事件,每隔幾毫秒就重新繪製JPanel,並認爲這將繼續在後臺重繪JPanel,並因此顯示查找解決方案的進度。這給了我雖然運行時錯誤:在線程 「AWT-EventQueue的-0」 顯示java.lang.NullPointerException

異常在遊戲$ 1.actionPerformed(Game.java:54) 在javax.swing.Timer中。在javax.swing.Timer中的fireActionPerformed(Timer.java:313) $ java.util.event.InvocationEvent.dispatch(InvocationEvent.java:311)處的$ DoPostEvent.run(Timer.java:245) at java.awt。 EventQueue.dispatchEventImpl(EventQueue.java:756) at java.awt.EventQueue.access $ 500(EventQueue.java:97) at java.awt.EventQueue $ 3.run(EventQueue.java:709) at java.awt。 EventQueue $ 3.run(EventQueue.java:703) 在java.security.AccessController.doPrivileged(本機方法) 在java.security.ProtectionDomain $ JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) 在java.awt.EventQueue.dispatchEvent(EventQueue.java:726) 是java .awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) 在java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) 在java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) 在java.awt中(EventDispatchThread.java:101) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

關於如何從JButton啓動動畫的任何想法?我覺得這應該比我做的更簡單,因爲動畫本身就可以很好地工作,我只想讓它在點擊JButton時開始。我想我會從零代碼開始,並根據要求提供必要的。

Game.java

import java.awt.*; 
import java.awt.geom.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class Game { 
    private static MazeGrid scene; 
    private static JFrame frame; 
    private static JButton play; 
    private static JButton solve; 
    private static JButton exit; 
    private static Timer timer; 
    private static boolean s = false; 


    public static void init() { 
     scene = new MazeGrid(); 
     frame = new JFrame(); 
     play = new JButton("Play"); 
     solve = new JButton("Solve"); 
     exit = new JButton("Exit"); 
     frame.setResizable(false); 
     frame.setSize(900, 700); 
     frame.setLayout(null); 
     frame.setLocationRelativeTo(null); 

     scene.setSize(650, 680); 
     frame.add(scene, BorderLayout.CENTER); 
     play.setSize(100, 50); 
     play.setLocation(650, 10); 
     frame.add(play); 
     solve.setSize(100, 50); 
     solve.setLocation(770, 10); 
     frame.add(solve); 
     exit.setSize(100, 50); 
     exit.setLocation(650, 100); 
     frame.add(exit); 
     frame.setVisible(true); 
    } 


    public static void main(String[] args) throws InterruptedException { 
     ActionListener action = new ActionListener(){ 
      @Override 
      public void actionPerformed(ActionEvent ev) { 
       if (ev.getSource() == timer) { 
        scene.repaint(); 
        System.out.println("hello"); 
       } 

      } 
     }; 

     timer = new Timer(40, action); 
     timer.setInitialDelay(0); 
     timer.start(); 

     init(); 
     play.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       frame.setVisible(false); 
       init(); 
      } 
     }); 

     solve.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       scene.solve(1, 1, squares, 40); 
       timer.stop(); 
      } 
     }); 

     exit.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       frame.setVisible(false); 
       frame.dispose(); 
      } 
     }); 
    } 

} 

解決

private void solve(int x, int y, Squares squares, int delay) { 
    // reached middle 
    if (x == N/2 && y == N/2) 
     done = true; 
    if (x == 0 || y == 0 || x == N + 1 || y == N + 1) 
     return; 
    if (done || m.Visited(x, y)) 
     return; 

    m.setVisited(x, y, true); 

    if (!(x == 1 & y == 1)) { 
     squares.getSquare(x, y).setPath(new Color(180, 140, 50)); 
     try { 
      Thread.sleep(delay); 
     } catch (InterruptedException e) { 
      System.err.println("Error while sleeping!"); 
      Thread.currentThread().interrupt(); 
     } 

     repaint(); 
    } 

    if (!m.Top(x, y)) 
     solve(x, y + 1, squares, delay); 
    if (!m.Right(x, y)) 
     solve(x + 1, y, squares, delay); 
    if (!m.Bottom(x, y)) 
     solve(x, y - 1, squares, delay); 
    if (!m.Left(x, y)) 
     solve(x - 1, y, squares, delay); 

    if (done) 
     return; 
    if (!(x == 1 & y == 1)) { 
     squares.getSquare(x, y).setPath(new Color(230, 230, 230)); 
     try { 
      Thread.sleep(delay); 
     } catch (InterruptedException e) { 
      System.err.println("Error while sleeping!"); 
      Thread.currentThread().interrupt(); 
     } 
     repaint(); 
    } 
} 
+0

請將完整的堆棧跟蹤與源代碼一起發佈。 – Berger

+0

這是你的意思嗎? – Novice

+0

是的,但我們需要知道'actionPerformed'中發生了什麼,所以請添加'Game'類。 – Berger

回答

0

我實現了我的理想效果使用SwingWorker像這樣:

class Solver extends SwingWorker<Integer, Integer> { 
    int delay; 

    Solver (int delay) { 
     this.delay = delay; 
    } 

    protected Integer doInBackground() throws Exception { 
     scene.solve(delay); 
     return 1; 
    } 
} 

,並已將此添加的JButton:

@Override 
public void actionPerformed(ActionEvent e) { 
    new Solver(40).execute(); 
} 

感謝試圖幫助。

1

呼叫init()開始YOUT Timer之前,或scene對象可能是null當它試圖訪問它。

 init(); 

    ActionListener action = new ActionListener(){ 
       @Override 
       public void actionPerformed(ActionEvent ev) { 
        if (ev.getSource() == timer) { 
         scene.repaint(); 
         System.out.println("hello"); 
        } 

       } 
      }; 

    timer = new Timer(40, action); 
    timer.setInitialDelay(0); 
    timer.start(); 
+0

這很有道理,但它沒有解決它。看起來,當我點擊解決按鈕時,定時器動作暫停(通過「你好」停止打印出來的事實來判斷)。編輯:要清楚,它確實修復了運行時錯誤,但解決方案仍然不能逐步打印出來。 – Novice

+0

您可能希望爲您的「solve」動作使用另一個計時器,因爲在EDT上調用了「Thread.sleep(delay)」語句並阻止任何重繪:http://stackoverflow.com/questions/4215968/java-線程睡眠看跌期權擺動的UI至睡眠太 – Berger