I've reduced the question to just the problem, so I'm making a UI for minesweeper game, in the controller below, in the StartGame method, things are well (according to my check using debug) until the line of
game.open(x,y)
, meaning I manage to create the board and add buttons (which will act as the slots) to the GridPane, but my issue is that I can't seem to open and show the correct value on the slot. (the logics of Mines class works fine - the one without the javaFX part).
package MS;
import java.io.IOException;
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class NewGameCONTROLLER {
Mines game;
int rows, columns, mines;
Button b;
@FXML
private TextField NumRows;
@FXML
private TextField NumCols;
@FXML
private TextField NumM;
@FXML
private Button StartGame;
@FXML
private Button BackMainMenu;
@FXML
private Button RandomGame;
@FXML
void BackMainMenu(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(); // Create loading object
loader.setLocation(getClass().getResource("MainMenuFXML.fxml")); // fxml location
VBox root = loader.load(); // Load layout
root.setStyle("-fx-background-image: url(\"file:///C:/EclipseProjects/MineSweeper/src/MS/menu.jpg\")");
Scene scene = new Scene(root); // Create scene with chosen layout
Stage primaryStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
primaryStage.setTitle("..."); // Set stage's title
primaryStage.setMinWidth(400); // Won't be allowed to make width/height smaller
primaryStage.setMinHeight(350);
primaryStage.setMaxWidth(600);
primaryStage.setMaxHeight(450);
primaryStage.setScene(scene); // Set scene to stage
primaryStage.show(); // Show stage
}
@FXML
void RandomGame(ActionEvent event) {
Random rand = new Random();
int low = 3, high = 15;
int minesLow = 1, minesHigh;
rows = rand.nextInt(high - low) + low;
columns = rand.nextInt(high - low) + low;
minesHigh = rows * columns - 1;
mines = rand.nextInt(minesHigh - minesLow) + minesLow;
game = new Mines(rows, columns, mines);
}
@FXML
void StartGame(ActionEvent event) throws IOException {
rows = Integer.parseInt(NumRows.getText());
columns = Integer.parseInt(NumCols.getText());
mines = Integer.parseInt(NumM.getText());
game = new Mines(rows, columns, mines);
FXMLLoader loader = new FXMLLoader(); // Create loading object
loader.setLocation(getClass().getResource("BoardFXML.fxml")); // fxml location
AnchorPane root = loader.load(); // Load layout
root.setStyle("-fx-background-image: url(\"file:///C:/EclipseProjects/MineSweeper/src/MS/Pic.jpg\")");
Scene scene = new Scene(root); // Create scene with chosen layout
Stage gameStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
gameStage.setTitle("..."); // Set stage's title
gameStage.setMinWidth(1000); // Won't be allowed to make width/height smaller
gameStage.setMinHeight(500);
gameStage.setMaxWidth(1200);
gameStage.setMaxHeight(800);
gameStage.setScene(scene); // Set scene to stage
BoardCONTROLLER bCont = loader.getController(); // Prepare board in BoardCONTROLLER
for (int i = 0; i < columns; i++)
for (int j = 0; j < rows; j++) {
b = new Button(" ");
b.setMinSize(40, 40);
b.setMaxSize(40, 40);
bCont.TheBoard.add(b, i, j);
}
for (int i = 0; i < bCont.TheBoard.getChildren().size(); i++) {
((ButtonBase) bCont.TheBoard.getChildren().get(i)).setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int x, y;
event.getSource();
x = (int) ((Button) event.getSource()).getProperties().get("gridpane-column");
y = (int) ((Button) event.getSource()).getProperties().get("gridpane-row");
game.open(x, y);
for (int i=0;i<game.getCol();i++)
for (int j=0;i<game.getRow();j++) {
if (game.board[i][j].charAt(1)=='T')
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
/* while ()
for (int i = 0; i < bCont.TheBoard.getChildren().size(); i++) {
if (game.board[x][y].charAt(2) == 'B') {
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
}*/
}
});
}
gameStage.show(); // Show stage
}
}
Thank you.
When I look at this loop.
for (int i=0;i<game.getCol();i++)
for (int j=0;i<game.getRow();j++) {
if (game.board[i][j].charAt(1)=='T')
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
}
The variable i
does not correspond to a row coordinate, it corresponds to the n'th child in the board. So really, your just looping through the all of the children in the first row (or first column).
On way I can see to fix that;
for( Node child: bCont.TheBoard.getChildren() ){
int i = (int) ((Button) child).getProperties().get("gridpane-column");
int j = (int) ((Button) child).getProperties().get("gridpane-row");
if (game.board[i][j].charAt(1)=='T'){
((Button) child).setText(game.get(x, y));
}
}
That way you go through all the children and check their status on the board.
I don't know if the order of the children nodes in GridPane correspond to the layout order, a common technique to pack a 2D array into a 1D array,
bCont.TheBoard.getChildren().get(i + j*game.getCol());
Remember you have row x col total buttons.