创建一个逐步更新JPanel的ActionListener

时间:2016-11-24 09:47:36

标签: java swing timer

我正在尝试制作一个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();
    }
}

2 个答案:

答案 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();
}

感谢你们的帮助。