好的,我根据需要编写了MCVE。关键是我正在训练从另一个线程(RecursiveThread)重绘MazePanel,但是它不起作用。仅在RecursiveThread结束工作时才重涂JPanel。
MCVE:
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import com.sun.prism.Graphics;
public class Main {
public static Gui gui;
public static int[] directionArray = {0, 1, 2, 3};
public static int[][] maze = {
{2, 2, 2, 0, 2, 2, 2},
{2, 1, 1, 1, 2, 1, 2},
{2, 1, 2, 2, 2, 1, 2},
{2, 1, 1, 1, 1, 1, 2},
{2, 2, 2, 3, 2, 2, 2}
};
public static RecursiveAlgorithm recursiveAlgorithm;
public static Thread alghoritmThread;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
gui = new Gui();
}
});
}
}
class MazePanel extends JPanel {
private int rows;
private int columns;
@Override
protected void paintComponent(java.awt.Graphics g) {
super.paintComponent(g);
rows = Main.maze.length;
columns = Main.maze[0].length;
Graphics2D g2 = (Graphics2D) g;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
switch (Main.maze[r][c]) {
case 0:
g2.setColor(Color.BLUE);
break;
case 1:
g2.setColor(Color.GRAY);
break;
case 2:
g2.setColor(Color.GREEN);
break;
case 3:
g2.setColor(Color.RED);
break;
case 4:
g2.setColor(Color.YELLOW);
break;
case 5:
g2.setColor(Color.BLACK);
break;
default:
break;
}
g.fillRect(c * 64, r * 64, 64, 64);
}
}
}
public void paint(Graphics g) {
}
}
class GuiActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == Gui.startButton) {
Main.recursiveAlgorithm = new RecursiveAlgorithm();
Main.alghoritmThread = new Thread(Main.recursiveAlgorithm);
Main.alghoritmThread.run();
}
}
}
class Gui extends JFrame {
public static JScrollPane scrollPane;
public static MazePanel mazePanel;
private JMenuBar menuBar;
public static JButton startButton;
public Gui() {
setPreferredSize(new Dimension(800, 600));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
startButton = new JButton("START");
startButton.addActionListener(new GuiActionListener());
menuBar = new JMenuBar();
menuBar.add(startButton);
mazePanel = new MazePanel();
scrollPane = new JScrollPane(mazePanel);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.LIGHT_GRAY);
setJMenuBar(menuBar);
add(scrollPane);
pack();
setVisible(true);
}
}
class RecursiveAlgorithm implements Runnable{
private int columns;
private int rows;
private int startX;
private int startY;
public RecursiveAlgorithm() {
rows = Main.maze.length;
columns = Main.maze[0].length;
}
private boolean findPath(int x, int y) {
System.out.println("findPath("+ x + "," + y +")");
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
System.out.print(Main.maze[r][c]);
}
System.out.println();
}
if (y < 0 || y >= rows) return false;
if (x < 0 || x >= columns) return false;
if (Main.maze[x][y] == 3) {
Main.maze[x][y] = 5;
Main.gui.mazePanel.repaint();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
if (Main.maze[x][y] != 0)
if (Main.maze[x][y] != 1) return false;
Main.maze[x][y] = 5;
Main.gui.mazePanel.repaint();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (goInDirectory(0, x, y)) return true;
if (goInDirectory(1, x, y)) return true;
if (goInDirectory(2, x, y)) return true;
if (goInDirectory(3, x, y)) return true;
Main.maze[x][y] = 4;
Main.gui.mazePanel.repaint();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
private boolean goInDirectory(int index, int x, int y) {
switch (Main.directionArray[index]) {
case 0:
if (findPath(x,y-1)) return true;
break;
case 1:
if (findPath(x+1,y)) return true;
break;
case 2:
if (findPath(x-1,y)) return true;
break;
case 3:
if (findPath(x,y+1)) return true;
break;
}
return false;
}
private void findStart() {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
if (Main.maze[r][c] == 0) {
startX = r;
startY = c;
}
}
}
}
@Override
public void run() {
System.out.println("Thread started");
findStart();
boolean pathFound = findPath(startX, startY);
if (pathFound) {
System.out.println("Path found");
} else {
System.out.println("Path NOT found!");
}
}
}
问题2(题外话):在我的真实代码中,im在JPanel上绘制图像,并覆盖了MazePanel中的paint()而不是paintComponent()。对我来说很好。但是,当我尝试将代码从paint()移到paintComponent()时,它将停止工作(然后在我的MazePanel上什么都没画)。这是代码(可以正常工作):
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
public void paint(Graphics g) {
if(Main.mazeReady) {
rows = Main.maze.length;
columns = Main.maze[0].length;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
g.drawImage(Main.maze[r][c].getGraphic(),
c * TileGraphicsHandler.TILE_HEIGHT,
r * TileGraphicsHandler.TILE_WIDTH,
null);
}
}
}
}
那样就不起作用了:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(Main.mazeReady) {
rows = Main.maze.length;
columns = Main.maze[0].length;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
g.drawImage(Main.maze[r][c].getGraphic(),
c * TileGraphicsHandler.TILE_HEIGHT,
r * TileGraphicsHandler.TILE_WIDTH,
null);
}
}
}
}
public void paint(Graphics g) {
}
问题3(题外话):如何划分RecursiveAlgorithm,以便我可以向gui按钮“ STEP FORWARD”添加并以这种方式控制算法(通过注入算法并在RecursiveAlgorithm中仅移动一条/几行)?
最佳答案
让我看看是否可以为您提供一些基本建议。您附加的代码库很大,坦率地说,有点混乱。
不要覆盖paint()
方法。您已经正确覆盖了paintComponent(...)
,但是覆盖paint()
方法是不正确的,并且可能会导致问题。
您有一个MazePanel
类,该类具有给定Tile[][]
的Maze
句柄。考虑改为创建一个具有Maze
且与Tile[][]
关联的所有关联状态的Maze
类,然后可以从Maze
引用该MazePanel
。
将方法添加到您的Maze
类中,该方法可以一步一步解决迷宫问题(例如stepTowardsSolution()
)。它可以返回一个指示是否完成的枚举或布尔值。
在MazePanel
中,有一个称为solve()
的方法可以执行以下操作:
while(maze.stepTowardsSolution() != done) {
repaint();
sleepABit();
}