如何在方法中初始化后正确显示JFrame
问题描述:
这是一个很长的问题,请耐心等待一分钟。我正在制作一个生命游戏应用程序,它首先显示一个带有JButton网格的JFrame。如果你点击JButton,它的背景会变黑,再次激活时,它的背景会变回白色。我的代码:如何在方法中初始化后正确显示JFrame
public class Choose implements ActionListener {
public final static int DIMENSION = 50;
Color BLACK = new Color(0,0,0);
Color WHITE = new Color(255,255,255);
JFrame choose;
JButton[] choice;
JButton clear, fill, go;
JPanel baseChoose, baseFrame, buttonsAndText;
GridLayout base;
public Choose() {
choose = new JFrame("Make your own game");
choice = new JButton[DIMENSION*DIMENSION];
baseChoose = new JPanel();
baseChoose.setSize(500, 500);
buttonsAndText = new JPanel();
buttonsAndText.add(clear = new JButton("Clear"));
clear.addActionListener(this);
buttonsAndText.add(fill = new JButton("Fill"));
fill.addActionListener(this);
buttonsAndText.add(go = new JButton("Go"));
go.addActionListener(this);
base = new GridLayout(DIMENSION, DIMENSION);
base.setHgap(-1);
base.setVgap(-1);
baseChoose.setLayout(base);
choose.add(baseChoose);
choose.add(buttonsAndText);
JLabel text = new JLabel("Press 'Go' to start.");
buttonsAndText.add(text);
for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
baseChoose.add(choice[i] = new JButton());
choice[i].setBackground(WHITE);
choice[i].addActionListener(this);
}
choose.setSize(500, 800);
choose.setVisible(true);
choose.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
choose.setResizable(false);
}
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
if (b == choice[i]) {
if (b.getBackground() == BLACK) {
choice[i].setBackground(WHITE);
} else if (b.getBackground() == WHITE) {
choice[i].setBackground(BLACK);
}
}
}
if (b == clear) {
for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
choice[i].setBackground(WHITE);
}
choose.validate();
choose.repaint();
}
if (b == fill) {
for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
choice[i].setBackground(BLACK);
}
choose.validate();
choose.repaint();
}
if (b == go) {
int states[] = new int[DIMENSION*DIMENSION];
for (int i = 0; i < DIMENSION*DIMENSION; i++) {
System.out.println(choice[i].getBackground() == BLACK);
if (choice[i].getBackground() == BLACK) {
states[i] = 1;
} else if (choice[i].getBackground() == WHITE) {
states[i] = 0;
}
}
choose.dispose();
Gui own = new Gui(states);
}
}
}
在main方法我使这个类的一个实例,当你选择了你的按钮激活,您可以点击go
按钮实际显示生命游戏。
public class Gui {
public final static int DIMENSION = 50;
Color BLACK = new Color(0,0,0);
Color WHITE = new Color(255,255,255);
JFrame frame, ownFrame;
JPanel baseFrame;
GridLayout base;
public Gui(int[] states) {
frame = new JFrame("Game of Life by Boris Verwoerd");
baseFrame = new JPanel();
baseFrame.setSize(500, 500);
frame.add(baseFrame);
base = new GridLayout(DIMENSION, DIMENSION);
base.setHgap(-1);
base.setVgap(-1);
baseFrame.setLayout(base);
JPanel[] box = new JPanel[DIMENSION*DIMENSION];
for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
baseFrame.add(box[i] = new JPanel());
box[i].setBorder(BorderFactory.createLineBorder(Color.black));
}
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.validate();
frame.repaint();
gameLoop(box, frame, states);
}
private static void gameLoop(JPanel[] boxes, JFrame theFrame, int[] states) {
int[] newstates = new int[DIMENSION*DIMENSION];
for (int i = 0; i < 20; i++) {
newstates = Maths.render(boxes, theFrame, states);
states = newstates;
theFrame.validate();
theFrame.repaint();
try {
Thread.sleep(100); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
public static int getDim() {
return DIMENSION;
}
}
当按下去,一个新的JFrame发布会但是屏幕全白,只有在gameLoop结束它显示的JPanel的网格。
只有当我使用全零阵列states
的主要方法制作Gui实例时,它才能正确显示它。 我已经尝试了很多东西来拿出一个解决方案,但我不明白为什么它导致这个白色的屏幕,而不是网格。因此,我的问题是:如何正确显示Gui的实例,在从方法初始化时没有白屏?
- 对不起,很长的职位/代码!
编辑:
这是我的数学类:
public class Maths {
static Color BLACK = new Color(0,0,0);
static Color WHITE = new Color(255,255,255);
public static int[] render(JPanel[] box, JFrame frame, int[] state) {
int[] newstates = new int[Gui.getDim()*Gui.getDim()];
for (int i = 0; i < (Gui.getDim()*Gui.getDim()); i++) newstates[i] = 0;
for (int i = (Gui.getDim()+1); i < (Gui.getDim()*Gui.getDim() - (Gui.getDim()+1)); i++) {
if (state[i] == 1) {
int aliveNeighbours = 0;
if (state[i-(Gui.getDim()+1)] == 1) aliveNeighbours++;
if (state[i-Gui.getDim()] == 1) aliveNeighbours++;
if (state[i-(Gui.getDim()-1)] == 1) aliveNeighbours++;
if (state[i-1] == 1) aliveNeighbours++;
if (state[i+1] == 1) aliveNeighbours++;
if (state[i+(Gui.getDim()-1)] == 1) aliveNeighbours++;
if (state[i+Gui.getDim()] == 1) aliveNeighbours++;
if (state[i+(Gui.getDim()+1)] == 1) aliveNeighbours++;
if (aliveNeighbours == 2 || aliveNeighbours == 3) {
box[i].setBackground(BLACK);
newstates[i] = 1;
} else {
box[i].setBackground(WHITE);
newstates[i] = 0;
}
} else if (state[i] == 0) {
int aliveNeighbours = 0;
if (state[i-(Gui.getDim()+1)] == 1) aliveNeighbours++;
if (state[i-Gui.getDim()] == 1) aliveNeighbours++;
if (state[i-(Gui.getDim()-1)] == 1) aliveNeighbours++;
if (state[i-1] == 1) aliveNeighbours++;
if (state[i+1] == 1) aliveNeighbours++;
if (state[i+(Gui.getDim()-1)] == 1) aliveNeighbours++;
if (state[i+Gui.getDim()] == 1) aliveNeighbours++;
if (state[i+(Gui.getDim()+1)] == 1) aliveNeighbours++;
if (aliveNeighbours == 3) {
box[i].setBackground(BLACK);
newstates[i] = 1;
} else {
box[i].setBackground(WHITE);
newstates[i] = 0;
}
}
}
return newstates;
}
}
答
你是一个Swing线程问题的经典案例,在这里它是由于有长时间运行的代码,也在Swing事件线程上调用Thread.sleep(...)
,这将使整个GUI进入睡眠状态,当然不是您的目标。
的解决方案是与任何类似的问题(你应该已经寻找和发现在这里发帖前):使用背景SwingWorker线程如果你调用代码反复与延迟长时间运行的代码,或Swing Timer 。
您在这里使用将取决于如何慢Maths.render
是。如果这个计算速度非常快,那么你所需要的只是一个摆动计时器来间歇地和延迟地进行这个通话。如果此方法需要大量时间来执行,那么您将需要使用SwingWorker路由。
例如,计时器代码可能看起来像:
private void gameLoop() {
int timerDelay = 100;
new Timer(timerDelay, new ActionListener() {
private final int maxIndex = 20;
private int index = 0;
@Override
public void actionPerformed(ActionEvent e) {
if (index < maxIndex) {
states = Maths.render(box, frame, states);
frame.validate();
frame.repaint();
} else {
((Timer) e.getSource()).stop();
}
index++;
}
}).start();
}
注意gameLoop应该是一个非静态实例方法。我还没有允许参数通道,而是由类的这些家伙领域:
并提出一定要设置这些字段:
public Gui(int[] states) {
this.states = states;
frame = new JFrame("Game of Life by Boris Verwoerd");
baseFrame = new JPanel();
baseFrame.setSize(500, 500);
frame.add(baseFrame);
base = new GridLayout(DIMENSION, DIMENSION);
base.setHgap(-1);
base.setVgap(-1);
baseFrame.setLayout(base);
box = new JPanel[DIMENSION * DIMENSION];
for (int i = 0; i < (DIMENSION * DIMENSION); i++) {
baseFrame.add(box[i] = new JPanel());
box[i].setBorder(BorderFactory.createLineBorder(Color.black));
}
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.validate();
frame.repaint();
gameLoop();
}
感谢您的回复,我肯定想谷歌它,但从来没有想出这个。你可以看看我的数学课,并确定它是否快速?我仍然是一个初学者程序员,我不知道这个班级是快还是慢。 – tomishomo 2014-10-28 21:52:51
@BorisVerwoerd:请检查编辑回答。你将不得不测试你的代码,看它是快还是慢。 – 2014-10-28 22:08:56
试过了,它完美的工作,我从来没有想到我的方法运行缓慢,但我不知道什么时候被认为是缓慢或快速。谢谢你的回答,我今天学到了一些新东西! – tomishomo 2014-10-28 22:13:28