I am designing a Checkers Game and once the game is finished, a new window opens where you have the possibility to either start a new game or quit. I don't know much about JavaFX and I have been trying for a while now to get my code to work, but I stand without success...
I have the difficulty, that my board is not displayed as a fxml file, but it is being created with javacode and put in the center of my borderPane. The top of the borderPane is fxml-file. Then, the other window, once the game is over, is also another fxml-file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<Pane fx:id="paneMenu" nodeOrientation="LEFT_TO_RIGHT" prefHeight="160.0" prefWidth="240.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.GameMenuController">
<children>
<Button fx:id="buttonRestart" layoutX="15.0" layoutY="122.0" mnemonicParsing="false" onAction="#restart" prefHeight="27.0" prefWidth="90.0" text="New Game" />
<Button fx:id="buttonQuit" layoutX="139.0" layoutY="122.0" mnemonicParsing="false" onAction="#quit" prefHeight="27.0" prefWidth="90.0" text="Quit" />
<Label fx:id="labelWinner" alignment="CENTER" contentDisplay="CENTER" layoutX="23.0" layoutY="80.0" prefHeight="17.0" prefWidth="190.0" text="Label" textAlignment="CENTER" />
<Text layoutX="50.0" layoutY="47.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Game over!" textAlignment="CENTER">
<font>
<Font size="26.0" />
</font>
</Text>
</children>
<padding>
<Insets bottom="10.0" right="10.0" />
</padding>
</Pane>
My Controller class for this fxml-file looks as follows:
public class GameMenuController implements Initializable {
public GameMenuController(Checkers model) {
this.content = model;
}
Checkers content;
@FXML
private Label labelWinner;
@FXML
private Button buttonRestart;
@FXML
private Button buttonQuit;
@FXML
private Pane paneMenu;
BooleanProperty doRestart = new SimpleBooleanProperty(false);
@FXML
void restart(ActionEvent event) {
content.cleanup();
doRestart.set(true);
}
@FXML
void quit(ActionEvent event) {
System.exit(0);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
labelWinner.setText("Winner here.");
labelWinner.textProperty().bind(Bindings.createStringBinding(() -> {
String s = " ";
if (...);
return s;
}, content.whiteTurnProp));
}
}
And finally, in my main class I wanted to add a ChangeListener to the value doRestart in order to then recreate a new Scene.
My main class looks something like this:
public class Main extends Application{
Checkers content = new Checkers();
BorderPane border = new BorderPane();
Pane paneBoard = new Pane();
FXMLLoader loader1 = new FXMLLoader();
FXMLLoader loader2 = new FXMLLoader();
@Override
public void start(Stage primaryStage) throws Exception {
loader1.setLocation(getClass().getResource("sample.fxml"));
loader1.setControllerFactory(new Callback<Class<?>, Object>() {
@Override
public Object call(Class<?> aClass) {
return new SampleController(content);
}
});
loader2.setLocation(getClass().getResource("GameMenu.fxml"));
loader2.setControllerFactory(new Callback<Class<?>, Object>() {
@Override
public Object call(Class<?> aClass) {
return new GameMenuController(content);
}
});
GameMenuController gameMenuControl = loader2.getController();
Scene scene = new Scene(startGame());
primaryStage.setTitle("Checkers");
primaryStage.setScene(scene);
primaryStage.show();
content.gameOver.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
try {
scene.setRoot(loader2.load());
primaryStage.setHeight(180);
primaryStage.setWidth(240);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
gameMenuControl.doRestart.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if(newValue) {
scene.setRoot(startGame());
primaryStage.setHeight(scene.getHeight());
primaryStage.setWidth(scene.getWidth());
gameMenuControl.doRestart.set(false);
}
}
});
}
public static void main(String[] args) {
launch(args);
}
protected Pane createContent() {
paneBoard.setPrefSize(Checkers.WIDTH * Checkers.TILE_SIZE, Checkers.HEIGHT * Checkers.TILE_SIZE);
paneBoard.getChildren().addAll(content.tileGroup, content.pieceGroup);
for (int y = 0; y < Checkers.HEIGHT; y++) {
for (int x = 0; x < Checkers.WIDTH; x++) {
Tile tile = new Tile((x + y) % 2 == 0, x, y);
Checkers.board[y][x] = tile;
content.tileGroup.getChildren().add(tile);
Piece piece = null;
if (y <= 3 && (x + y) % 2 != 0) {
piece = content.makePiece(PieceType.BLACK, x, y);
}
if (y >= 6 && (x + y) % 2 != 0) {
piece = content.makePiece(PieceType.WHITE, x, y);
}
if (piece != null) {
tile.setPiece(piece);
content.pieceGroup.getChildren().add(piece);
}
}
}
return paneBoard;
}
protected BorderPane startGame() {
try {
border.setTop(loader1.load());
} catch (IOException e) {
e.printStackTrace();
}
border.setCenter(createContent());
return border;
}
}
I am pretty sure that my code is a mess, I have been trying to work in as much of the tips given on here as possible, but since I am still super new to this, I don't really know how to go about it all.
What I would like to do, instead of using this change listener (which also doesn't work yet, Iam getting a NullPointerException), I'd like to change the view directly from my controller. How would I go about this?
1) Instead of creating the Controllers via Factory, can I give them somehow else access to my model Checkers? (all the game logic is stored there etc.)
2) How do I basically then recreate my first window? (created by startGame())
Thank you very much!! Best, Lisa