Component / JPanel repaint()方法问题

时间:2016-03-17 21:03:51

标签: java swing jpanel repaint

我正在努力制作康威的生活游戏,但我在使用repaint()方法时遇到了问题。我创建了一个扩展JPanel的类,当我覆盖绘制时我调用super.paint(g),而且我没有覆盖repaint()方法,但我没有运气。我在这里测试的主要方法是(请原谅我可怕的标识符):

import javax.swing.JFrame;

public class YouThinkThisIsAGame extends JFrame {
private Life facebook;

public YouThinkThisIsAGame() {
    super("I'm Blue da ba dee da ba die");
    Life kyle = new Life();
    add(kyle);
    //setSize(kyle.getALife()[0].length * 5, kyle.getALife().length * 5);
    setSize(500, 500);
    setVisible(true);
    setMaximumSize(getSize());
    setMinimumSize(getSize());
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
    YouThinkThisIsAGame stuff = new YouThinkThisIsAGame();
    while (true) {
        stuff.facebook.repaint();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
}

JPanel扩展课程在这里:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;

public class Life extends JPanel {

private Cell[][] grid;
Color life;

{
    life = new Color(0, 175, 0);
    initializeGrid(1300, 800, 0.025);
}

public void paint(Graphics G) {
    super.paint(G);
    Graphics2D g2d = (Graphics2D) G;
    drawGrid(g2d);
}


/** Me attempting to be funny */
public String getLife() {
    return null;
}

/** Also trying to be funny */
public Cell[][] getALife() {
    return grid;
}


public void drawGrid(Graphics2D g) {
    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[i].length; j++) {
            if (grid[i][j].isLiving) {
                g.setColor(life);
                //g.setColor(Color.WHITE);
            } else {
                g.setColor(Color.BLACK);
            }
            g.fillRect(i * 5, j * 5, 5, 5);
        }
    }
}

/** Allocates a new grid of cells of the requested dimensions and 
 * sets each cell in the grid to a random living/dead state.
 * The desired percentage of living cells is passed as a
 * parameter.
 * 
 * @double percent roughly, the percentage of cells that should
 *   be initialized as alive
 */
public void initializeGrid(int rows, int cols, double percent) {
    grid = new Cell[rows][cols];
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            grid[i][j] = new Cell();
            double x = Math.random();
            if (x > percent) {
                grid[i][j].setLiving(false);
            } else {
                grid[i][j].setLiving(true);
            }
        }
    }
}

/** Displays the contents of the grid to the standard output.
 */
public void displayGrid() {
    for (Cell[] cellRow : grid) {
        for (Cell c : cellRow) {
            if (c.isLiving()) System.out.print("0");
            else System.out.print("1");
        }
        System.out.println();
    }

}

/** Updates the value of each cell in the array according to
 * the rules of life: 
 * If the cell is currently living --
 *   if fewer than two neighboring cells are alive, die (loneliness)
 *   if two or three neighboring cells are alive, live
 *   if four or more neighboring cells are alive, die (overcrowding)
 * If the cell is currently dead -- 
 *   if precisely three neighboring cells are alive, become alive
 */
public void updateGrid() {
    Cell[][] gridCopy = new Cell[grid.length][grid[0].length];
    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[i].length; j++) {
            Cell c = new Cell();
            c.setLiving(grid[i][j].isLiving);
            gridCopy[i][j] = c;
        }
    }
    for (int i = 1; i < grid.length - 1; i++) {
        for (int j = 1; j < grid[i].length - 1; j++) {
            int adjacentAlive = 0;
            if (i == 2 && (j == 4 || j == 3)) {
                System.out.print("");
            }
            if (i == 3 && j == 4) {
                System.out.print("");
            }
            if (gridCopy[i - 1][j - 1].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i][j - 1].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i + 1][j - 1].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i - 1][j].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i + 1][j].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i - 1][j + 1].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i][j + 1].isLiving) {
                adjacentAlive++;
            }
            if (gridCopy[i + 1][j + 1].isLiving) {
                adjacentAlive++;
            }
            if (adjacentAlive == 3) {
                grid[i][j].setLiving(true);
            }else if (adjacentAlive == 2) {

            } else {
                grid[i][j].setLiving(false);
            }
        }
    }
    System.out.println("");
}

/** Convenience method for setting the grid values.
 * 
 * @param grid a two dimensional table of Cells
 */
public void setGrid(Cell[][] grid) {
    this.grid = grid;
}

public static void main(String[] args) {
    Life life = new Life();
    life.initializeGrid(15, 40, 0.25);
    life.displayGrid();
    while (true){
        try {
            Thread.sleep(250);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        life.updateGrid();
        life.displayGrid();
    }
}

class Cell {
    private boolean isLiving;

    public void setLiving(boolean isLiving) {
        this.isLiving = isLiving;
    }
    public boolean isLiving() {
        return isLiving;
    }
}
}

1 个答案:

答案 0 :(得分:2)

你有两个主要方法,我假设你运行的是YouThinkThisIsAGame类中的方法。如果是这样,你永远不会从这个main方法调用Life对象上的updateGrid()(但你在其他 main方法中),所以网格永远不会更新。

建议:

  • 在主方法中创建一个线程,
  • 传入一个具有while (true)循环的Runnable。
  • 在该循环中,在可视化的Life实例
  • 上调用updateGrid()
  • 并在Life实例上调用repaint()
  • 创建后在该线程上调用start()
  • 请注意,最好在JPanel的paintComponent覆盖范围内绘制,而不是绘制方法。
  • 并在该覆盖范围内调用super.paintComponent(...)
  • 始终在覆盖方法之前加上@Override注释,让编译器检查您实际上是否覆盖了该方法。
  • 修复您现在告诉我们的NullPointerException。您永远不会初始化或使用facebook字段,而是使用在YouThinkThisIsAGame构造函数内部声明的影子变量kyle。这是唯一可行的Life实例。
  • 所以摆脱kyle变量,而不是初始化并使用facebook字段。
  • 并避免直接访问对象的任何字段。而是通过该类的公共方法,您应该为此创建一个方法,以便在 可视化 上再次调用updateGrid()repaint()生活实例(这就是为什么我上面提到的可视化 - 这是关键)。
例如,像:

import javax.swing.JFrame;

public class YouThinkThisIsAGame extends JFrame {
    private Life life;  // renamed to life

    public YouThinkThisIsAGame() {
        super("I'm Blue da ba dee da ba die");

        // no -- don't create a new Life variable!
        // Life kyle = new Life();
        // add(kyle);

        life = new Life(); // initialize and use the **field**
        add(life);  // and place it into the JFrame

        setSize(500, 500); // better to have Life override getPreferredSize
        setVisible(true);
        setMaximumSize(getSize());
        setMinimumSize(getSize());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void updateLife() {
        life.updateGrid();
        life.repaint();
    }

    public static void main(String[] args) {
        final YouThinkThisIsAGame stuff = new YouThinkThisIsAGame();
        new Thread(() -> {
            while (true) {
                stuff.updateLife();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}