在线程算法工作期间重新绘制JPanel

时间:2015-06-18 16:12:16

标签: java multithreading swing parallel-processing jpanel

好的,我按你的意愿写了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(offtopic):在我的真实代码中,我在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(offtopic):如何划分我的RecursiveAlgorithm,所以我可以添加gui按钮“STEP FORWARD”并以这种方式控制我的算法(通过在我的RecursiveAlgorithm中移动alghoritm并只移动一行/几行) ?

1 个答案:

答案 0 :(得分:3)

让我看看能否为您提供一些基本建议。您附加的代码库相当大,坦率地说,有点混乱。

  1. 不要覆盖paint()方法。您已正确覆盖paintComponent(...),但覆盖paint()方法不正确,可能会导致问题。
  2. 您有一个MazePanel类,其中包含Tile[][]给定Maze的句柄。请考虑创建一个Maze类,其中包含Tile[][],以及与Maze相关联的所有关联状态,然后您可以从{Maze引用MazePanel {1}}。
  3. Maze课程添加一个方法,该方法可以向迷宫的解决方案迈出一步(例如stepTowardsSolution())。它可以返回一个枚举或布尔值,表示它是否已完成。
  4. MazePanel中,有一个名为solve()的方法:

    while(maze.stepTowardsSolution() != done) {
        repaint();
        sleepABit();
    }