我正在尝试制作一个JButton 启动一个解决迷宫的动画。我有一个递归的,深度优先的搜索函数,它找到路径,但逐步着色(使用Thread.sleep()
)。代码完美无缺。我遇到的问题是有一个按钮开始这个动画。
当我将函数添加到JButton的actionPerformed
中时,解决方案只有在完全完成后才会出现(不是一步一步)。我得知这是因为动作侦听器是单线程或类似的东西,所以我尝试使用Swing Timer。我只是创建了一个每隔几毫秒重新绘制JPanel的事件,认为这会在后台重新绘制JPanel,从而显示找到解决方案的进度。这给了我一个运行时错误:
线程“AWT-EventQueue-0”中的异常java.lang.NullPointerException 在游戏$ 1.actionPerformed(Game.java:54) 在javax.swing.Timer.fireActionPerformed(Timer.java:313) 在javax.swing.Timer $ DoPostEvent.run(Timer.java:245) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311) 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) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain $ JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:726) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) 在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 :(得分:1)
在您启动init()
之前致电Timer
,或者scene
对象在尝试访问时null
。{/ p>
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();
答案 1 :(得分: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();
}
感谢你们的帮助。