我試圖做一個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();
}
}
請將完整的堆棧跟蹤與源代碼一起發佈。 – Berger
這是你的意思嗎? – Novice
是的,但我們需要知道'actionPerformed'中發生了什麼,所以請添加'Game'類。 – Berger