java - Component/JPanel repaint() 方法问题

标签 java swing jpanel repaint

我正在尝试制作康威的生命游戏,但在使用 repaint() 方法时遇到问题。我创建了一个扩展 JPanel 的类,并且当我重写 Paint 时调用 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;
    }
}
}

最佳答案

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

建议:

  • 在主方法中创建一个线程,
  • 传入一个具有 while (true) 循环的 Runnable。
  • 在该循环中,对可视化 Life 实例调用 updateGrid()
  • 并在 Life 实例上调用 repaint()
  • 创建后在该线程上调用 start()
  • 请注意,您最好在 JPanel 的 PaintComponent 重写中进行绘制,而不是在 Paint 方法中进行绘制。
  • 并在该覆盖中调用 super.paintComponent(...)
  • 始终在重写方法前添加 @Override 注解,以便编译器检查您是否确实重写了该方法。
  • 修复您现在告诉我们的 NullPointerException。您从未初始化或使用 facebook 字段,而是使用在 YouThinkThisIsAGame 构造函数内部声明的影子变量 kyle。这是唯一可行的 Life 实例。
  • 因此,摆脱 kyle 变量,而是初始化并使用 facebook 字段。
  • 并避免直接访问对象的任何字段。相反,您应该通过该类的公共(public)方法,并且您应该为此创建一个方法,以便在 上再次调用 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();
    }
}

关于java - Component/JPanel repaint() 方法问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36071663/

相关文章:

java - 如何使用 Java SSH 读取/复制文件从 unix box 到 windows

java - 如何使用不同java类中的函数和变量?

java - 监听/处理 JPanel 事件

java - 添加一个在 JSplitpane 和 JPanel 之间拆分的 JScrollpane?

java - 从外部更改和更新 JPanel 组件,JFrame 不起作用,Swing

java - 合并排序,合并期间数组重新排列。 java

java - 正则表达式匹配用户代理中的版本号(没有应用程序中的名称)

JavaFX 禁用加速器操作

Java:如何在 JFrame/JPanel 中打开 Google 之类的网页?

java - 使用 For 语句创建按钮并将它们添加到面板中?