重新启动扫雷 GUI 程序
Restarting minesweeper GUI program
我制作了一个类似于扫雷的 GUI 游戏,尽管逻辑要少得多。基本上,用户单击 space 并查看下面是否有金子,如果没有,则显示 X。如果有,则显示金块。我想让游戏重新启动,一旦用户找到 10 块金币,所有数据都会重置。但是,我的 do while
循环没有成功。我已经注释掉了导致我出现问题的代码部分。每次我 运行 带有我已注释掉的内容的程序时,它都会卡住并且在我单击第一个按钮时不会继续 运行ning。否则,注释掉这些东西后,它会按应有的方式工作。
问:如何让我的程序在用户发现10个金币后重新启动并重置数据值?另外,为什么我设置的 12x12 按钮网格与我设置 2D 按钮阵列的方式不成比例?
这是我将 do while
注释掉后游戏的样子:
public class NuggetPanel extends JPanel {
// variable declaration
boolean restartGame = false;
JButton[][] buttons = new JButton[12][12];
JButton restart = new JButton("You win! Click to restart game");
int count = 0;
int goldFound = 0;
JLabel clickCount = new JLabel("Number of digs: " + count);
JLabel goldCount = new JLabel("Gold found: " + goldFound);
// sets up the panel
public NuggetPanel() {
setLayout(new GridLayout(12, 12, 2, 2));
JPanel LabelPane = new JPanel();
//creates 2D array of buttons
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
buttons[i][j] = new JButton("");
buttons[i][j].addActionListener(new buttonListener());
add(buttons[i][j]);
}
}
//adds components
LabelPane.add(clickCount);
LabelPane.add(goldCount);
LabelPane.add(restart);
add(LabelPane);
restart.setVisible(false);
}
// button is clicked
private class buttonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// do{
// finds which button was clicked
JButton buttonClicked = (JButton) e.getSource();
restartGame = false;
restart.setVisible(false);
// sets up gold array
Boolean[] randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
// iterates through button array
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (buttonClicked == buttons[i][j]) {
// if there is a gold under the square, shows gold icon
if (randomGold[i] == true) {
buttons[i][j].setIcon(new ImageIcon("./src/Gold.jpg"));
buttons[i][j].removeActionListener(this);
goldFound++;
count++;
clickCount.setText("Number of digs: " + count);
goldCount.setText("Gold found: " + goldFound + " ");
}
// if there is no gold under the square, shows X
else {
buttons[i][j].removeActionListener(this);
buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));
count++;
clickCount.setText("Number of digs: " + count);
goldCount.setText("Gold found: " + goldFound);
}
// if (goldFound == 10) {
// restart.setVisible(true);
// }
//
// if (buttonClicked == restart) {
// count = 0;
// goldFound = 0;
// clickCount.setText("Number of digs: " + count);
// for (int x = 0; i < buttons.length; i++)
// {
// for(int y = 0; j < buttons[i].length; j++)
// {
// buttons[x][y].setIcon(null);
// }
// }
// restartGame = true;
// }
j = buttons[i].length - 1;
i = buttons.length - 1;
}
}
}
// } while(restartGame = true);
}
}
}
Also, why is my 12x12 button grid I've set up showing up not proportional to how I set up the 2D button array?
这是一个双重问题。 JButton
具有 margin
通常不是正方形的属性。此外,当您将组件添加到 GridLayout
时,所有组件的大小都相同,因此当您将 LabelPane
添加到布局时,它会强制所有按钮至少具有它的宽度。
相反,使用 GridLayout
将按钮放在单独的面板上,然后使用 BorderLayout
将其和 LabelPanel 放在 NuggetPanel
上,例如...
public NuggetPanel() {
setLayout(new BorderLayout());
JPanel buttonPane = new JPanel(new GridLayout(12, 12, 2, 2));
//creates 2D array of buttons
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
// nb: I'd use a "blank" icon which was the same
// size as the other icons and set it as the
// buttons icon, this will ensure that the
// buttons are always the right size...
buttons[i][j] = new JButton("");
buttons[i][j].setMargin(new Insets(5, 5, 5, 5));
buttons[i][j].addActionListener(new buttonListener());
buttonPane.add(buttons[i][j]);
}
}
//adds components
JPanel LabelPane = new JPanel();
LabelPane.add(clickCount);
LabelPane.add(goldCount);
LabelPane.add(restart);
add(buttonPane);
add(LabelPane, BorderLayout.SOUTH);
restart.setVisible(false);
}
How can I make my program restart and the data values reset once a user uncovers 10 gold pieces?
这是一个更复杂的问题,需要您改变思维方式。
actionPerfomed
将在单击每个 ANY 按钮时调用,但您正在做的是随机化黄金的位置......这将使用户几乎不可能获胜。为什么?因为可以在已经检查过的按钮下放置一块金子...
@Override
public void actionPerformed(ActionEvent e) {
// finds which button was clicked
JButton buttonClicked = (JButton) e.getSource();
restartGame = false;
restart.setVisible(false);
// sets up gold array
Boolean[] randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
相反,创建一个可用于重置或初始化游戏状态的方法...
protected void reset() {
// sets up gold array
randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
// Reset the image icon with a blank image...
buttons[i][j].setText("");
buttons[i][j].setEnabled(true);
}
}
}
这也应该在构造函数的末尾调用。这将确保游戏处于可以玩的就绪状态...
而不是使用 buttons[i][j].removeActionListener(this);
,只需使用 buttons[i][j].setEnabled(false);
将按钮设置为禁用,这样可以更轻松地重置按钮,因为您无需关心按钮是否已经有ActionListener
是否与之关联(这可能导致您的 actionPerformed
方法被单个按钮多次调用 :P)
在您的 actionPerformed
方法结束时,您只需检查 goldFound
的数量并调用 reset
重置游戏...
if (goldFound == 10) {
JOptionPane.showMessageDialog(NuggetPanel.this, "You win");
reset();
}
其他...
不要使用诸如...
之类的方式从您的 src
目录加载资源
buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));
一旦构建代码,这将失败。相反,您需要将资源作为嵌入式资源引用并使用 Class#getResource
buttons[i][j].setIcon(new ImageIcon(getClass().getResource("/Missed.png")));
但坦率地说,这有点浪费,您可以改为将图标定义为常量....
public static final ImageIcon MISSED_ICON = new ImageIcon(getClass().getResource("/Missed.png")));
然后在需要时简单地引用它...
buttons[i][j].setIcon(MISSED_ICON);
就我个人而言,我更喜欢 ImageIO.read
,因为它抛出一个 IOException
,但它使设置常量变得更加复杂...
此外,我可能会考虑使用某种 List
来管理按钮和 "gold" 位置,因为它只是使用 List#indexOf(Object)
然后必须 运行每次都通过双循环...
我制作了一个类似于扫雷的 GUI 游戏,尽管逻辑要少得多。基本上,用户单击 space 并查看下面是否有金子,如果没有,则显示 X。如果有,则显示金块。我想让游戏重新启动,一旦用户找到 10 块金币,所有数据都会重置。但是,我的 do while
循环没有成功。我已经注释掉了导致我出现问题的代码部分。每次我 运行 带有我已注释掉的内容的程序时,它都会卡住并且在我单击第一个按钮时不会继续 运行ning。否则,注释掉这些东西后,它会按应有的方式工作。
问:如何让我的程序在用户发现10个金币后重新启动并重置数据值?另外,为什么我设置的 12x12 按钮网格与我设置 2D 按钮阵列的方式不成比例?
这是我将 do while
注释掉后游戏的样子:
public class NuggetPanel extends JPanel {
// variable declaration
boolean restartGame = false;
JButton[][] buttons = new JButton[12][12];
JButton restart = new JButton("You win! Click to restart game");
int count = 0;
int goldFound = 0;
JLabel clickCount = new JLabel("Number of digs: " + count);
JLabel goldCount = new JLabel("Gold found: " + goldFound);
// sets up the panel
public NuggetPanel() {
setLayout(new GridLayout(12, 12, 2, 2));
JPanel LabelPane = new JPanel();
//creates 2D array of buttons
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
buttons[i][j] = new JButton("");
buttons[i][j].addActionListener(new buttonListener());
add(buttons[i][j]);
}
}
//adds components
LabelPane.add(clickCount);
LabelPane.add(goldCount);
LabelPane.add(restart);
add(LabelPane);
restart.setVisible(false);
}
// button is clicked
private class buttonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// do{
// finds which button was clicked
JButton buttonClicked = (JButton) e.getSource();
restartGame = false;
restart.setVisible(false);
// sets up gold array
Boolean[] randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
// iterates through button array
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (buttonClicked == buttons[i][j]) {
// if there is a gold under the square, shows gold icon
if (randomGold[i] == true) {
buttons[i][j].setIcon(new ImageIcon("./src/Gold.jpg"));
buttons[i][j].removeActionListener(this);
goldFound++;
count++;
clickCount.setText("Number of digs: " + count);
goldCount.setText("Gold found: " + goldFound + " ");
}
// if there is no gold under the square, shows X
else {
buttons[i][j].removeActionListener(this);
buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));
count++;
clickCount.setText("Number of digs: " + count);
goldCount.setText("Gold found: " + goldFound);
}
// if (goldFound == 10) {
// restart.setVisible(true);
// }
//
// if (buttonClicked == restart) {
// count = 0;
// goldFound = 0;
// clickCount.setText("Number of digs: " + count);
// for (int x = 0; i < buttons.length; i++)
// {
// for(int y = 0; j < buttons[i].length; j++)
// {
// buttons[x][y].setIcon(null);
// }
// }
// restartGame = true;
// }
j = buttons[i].length - 1;
i = buttons.length - 1;
}
}
}
// } while(restartGame = true);
}
}
}
Also, why is my 12x12 button grid I've set up showing up not proportional to how I set up the 2D button array?
这是一个双重问题。 JButton
具有 margin
通常不是正方形的属性。此外,当您将组件添加到 GridLayout
时,所有组件的大小都相同,因此当您将 LabelPane
添加到布局时,它会强制所有按钮至少具有它的宽度。
相反,使用 GridLayout
将按钮放在单独的面板上,然后使用 BorderLayout
将其和 LabelPanel 放在 NuggetPanel
上,例如...
public NuggetPanel() {
setLayout(new BorderLayout());
JPanel buttonPane = new JPanel(new GridLayout(12, 12, 2, 2));
//creates 2D array of buttons
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
// nb: I'd use a "blank" icon which was the same
// size as the other icons and set it as the
// buttons icon, this will ensure that the
// buttons are always the right size...
buttons[i][j] = new JButton("");
buttons[i][j].setMargin(new Insets(5, 5, 5, 5));
buttons[i][j].addActionListener(new buttonListener());
buttonPane.add(buttons[i][j]);
}
}
//adds components
JPanel LabelPane = new JPanel();
LabelPane.add(clickCount);
LabelPane.add(goldCount);
LabelPane.add(restart);
add(buttonPane);
add(LabelPane, BorderLayout.SOUTH);
restart.setVisible(false);
}
How can I make my program restart and the data values reset once a user uncovers 10 gold pieces?
这是一个更复杂的问题,需要您改变思维方式。
actionPerfomed
将在单击每个 ANY 按钮时调用,但您正在做的是随机化黄金的位置......这将使用户几乎不可能获胜。为什么?因为可以在已经检查过的按钮下放置一块金子...
@Override
public void actionPerformed(ActionEvent e) {
// finds which button was clicked
JButton buttonClicked = (JButton) e.getSource();
restartGame = false;
restart.setVisible(false);
// sets up gold array
Boolean[] randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
相反,创建一个可用于重置或初始化游戏状态的方法...
protected void reset() {
// sets up gold array
randomGold = new Boolean[144];
// fills gold array with 10 true elements
for (int i = 0; i < randomGold.length; i++) {
randomGold[i] = false;
// sets 10 indexes in the array to true
if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
randomGold[i] = true;
}
}
// randomizes gold array
Collections.shuffle(Arrays.asList(randomGold));
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
// Reset the image icon with a blank image...
buttons[i][j].setText("");
buttons[i][j].setEnabled(true);
}
}
}
这也应该在构造函数的末尾调用。这将确保游戏处于可以玩的就绪状态...
而不是使用 buttons[i][j].removeActionListener(this);
,只需使用 buttons[i][j].setEnabled(false);
将按钮设置为禁用,这样可以更轻松地重置按钮,因为您无需关心按钮是否已经有ActionListener
是否与之关联(这可能导致您的 actionPerformed
方法被单个按钮多次调用 :P)
在您的 actionPerformed
方法结束时,您只需检查 goldFound
的数量并调用 reset
重置游戏...
if (goldFound == 10) {
JOptionPane.showMessageDialog(NuggetPanel.this, "You win");
reset();
}
其他...
不要使用诸如...
之类的方式从您的src
目录加载资源
buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));
一旦构建代码,这将失败。相反,您需要将资源作为嵌入式资源引用并使用 Class#getResource
buttons[i][j].setIcon(new ImageIcon(getClass().getResource("/Missed.png")));
但坦率地说,这有点浪费,您可以改为将图标定义为常量....
public static final ImageIcon MISSED_ICON = new ImageIcon(getClass().getResource("/Missed.png")));
然后在需要时简单地引用它...
buttons[i][j].setIcon(MISSED_ICON);
就我个人而言,我更喜欢 ImageIO.read
,因为它抛出一个 IOException
,但它使设置常量变得更加复杂...
此外,我可能会考虑使用某种 List
来管理按钮和 "gold" 位置,因为它只是使用 List#indexOf(Object)
然后必须 运行每次都通过双循环...