Issue
I'm making a javafx app and when I run it the IDE gives no errors. The application window doesn't show but I can see that the program's running in task manager.
I have tried running the code in both Eclipse and IntelliJ. I tried running a new application with just a title and it worked so it's something to do with the particular code.
package main;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.text.Font;
public class Main extends Application {
public boolean isX=true;
public Button[] bs=new Button[9];
Label turn = new Label("Turn: X");
public int i=0;
public void start(Stage stage){
BorderPane bp = new BorderPane();
bp.setPrefSize(310, 350);
turn.setFont(Font.font(20));
bp.setTop(turn);
makeButtons(bs);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.add(bs[0],0,0);
grid.add(bs[1],1,0);
grid.add(bs[2],2,0);
grid.add(bs[3],0,1);
grid.add(bs[4],1,1);
grid.add(bs[5],2,1);
grid.add(bs[6],0,2);
grid.add(bs[7],1,2);
grid.add(bs[8],2,2);
bp.setCenter(grid);
stage.setScene(new Scene(bp));
stage.setTitle("Tic tac toe");
stage.show();
}
void makeButtons(Button[] bs){
while (i<bs.length){
bs[i]=new Button(" ");
bs[i].setFont(Font.font("Monospaced", 40));
bs[i].setPrefSize(90, 90);
bs[i].setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
if (isX){
isX=false;
bs[i].setText("X");
turn.setText("Turn: O");
} else {
isX=true;
bs[i].setText("O");
turn.setText("Turn: X");
}
}
});
}
}
public static void main(String[] args){
launch(Main.class);
}
}
Update: I finished noughts and crosses
package main;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.text.Font;
public class Main extends Application {
public boolean isX=true;
public Button[] bs=new Button[9];
Label turn = new Label("Turn: X");
int goes =0;
public void start(Stage stage){
BorderPane bp = new BorderPane();
bp.setPrefSize(310, 350);
turn.setFont(Font.font(20));
bp.setTop(turn);
makeButtons(bs);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.add(bs[0],0,0);
grid.add(bs[1],1,0);
grid.add(bs[2],2,0);
grid.add(bs[3],0,1);
grid.add(bs[4],1,1);
grid.add(bs[5],2,1);
grid.add(bs[6],0,2);
grid.add(bs[7],1,2);
grid.add(bs[8],2,2);
bp.setCenter(grid);
stage.setScene(new Scene(bp));
stage.setTitle("Noughts and crosses");
stage.show();
}
void makeButtons(Button[] bs){
for (int i=0;i<bs.length;i++){
bs[i]=new Button(" ");
bs[i].setFont(Font.font("Monospaced", 40));
bs[i].setPrefSize(90, 90);
bs[i].setOnAction(this::handleTurn);
}
}
private void handleTurn(ActionEvent e){
goes++;
if (goes>4&&won()){
return;
}
Button b = (Button) e.getSource();
if (!b.getText().equals(" ")){
return;
}
if (isX) {
isX = false;
b.setText("X");
turn.setText("Turn: O");
} else {
isX=true;
b.setText("O");
turn.setText("Turn: X");
}
if (goes==9){
turn.setText("Game over: not turns left");
}
}
private boolean won(){
//rows
for (int i=0;i< 7;i+=3){
if (!bs[i].getText().equals(" ")&&bs[i].getText().equals(bs[i+1].getText())&&bs[i].getText().equals(bs[i+2].getText())){
turn.setText(bs[i].getText()+" wins!");
return true;
}
}
//columns
for (int i=0;i<3;i++){
if (!bs[i].getText().equals(" ")&&bs[i].getText().equals(bs[i+3].getText())&&bs[i].getText().equals(bs[i+6].getText())){
turn.setText(bs[i].getText()+" wins!");
return true;
}
}
//diagonals
if (!bs[0].getText().equals(" ")&&bs[0].getText().equals(bs[4].getText())&&bs[0].getText().equals(bs[8].getText())){
turn.setText(bs[0].getText()+" wins!");
return true;
}
if (!bs[2].getText().equals(" ")&&bs[2].getText().equals(bs[4].getText())&&bs[2].getText().equals(bs[6].getText())){
turn.setText(bs[2].getText()+" wins!");
return true;
}
return false;
}
public static void main(String[] args){
launch(Main.class);
}
}
Solution
You aren't changing the value of i
in the while
loop in method makeButtons
and therefore the while
loop never terminates.
Also, you should add an action listener to the buttons and not a mouse listener. Refer to this tutorial.
Consider the following code.
(Note: More explanations after the code.)
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.text.Font;
public class Main extends Application {
public boolean isX=true;
public Button[] bs=new Button[9];
Label turn = new Label("Turn: X");
public void start(Stage stage){
BorderPane bp = new BorderPane();
bp.setPrefSize(310, 350);
turn.setFont(Font.font(20));
bp.setTop(turn);
makeButtons(bs);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.add(bs[0],0,0);
grid.add(bs[1],1,0);
grid.add(bs[2],2,0);
grid.add(bs[3],0,1);
grid.add(bs[4],1,1);
grid.add(bs[5],2,1);
grid.add(bs[6],0,2);
grid.add(bs[7],1,2);
grid.add(bs[8],2,2);
bp.setCenter(grid);
stage.setScene(new Scene(bp));
stage.setTitle("Tic tac toe");
stage.show();
}
void makeButtons(Button[] bs){
int i = 0;
while (i<bs.length){
bs[i]=new Button(" ");
bs[i].setFont(Font.font("Monospaced", 40));
bs[i].setPrefSize(90, 90);
bs[i].setOnAction(this::handleTurn);
i++;
}
}
private void handleTurn(ActionEvent event) {
Button button = (Button) event.getSource();
if (isX) {
isX = false;
button.setText("X");
turn.setText("Turn: O");
}
else {
isX = true;
button.setText("O");
turn.setText("Turn: X");
}
}
public static void main(String[] args){
launch(Main.class);
}
}
The above code uses method references which were introduced in Java 8. Here is the relevant line from the above code:
bs[i].setOnAction(this::handleTurn);
Whenever any of the buttons are clicked, method handleTurn
is executed.
Notice that, in that method, I obtain the actual button that was clicked by calling method getSource
(of class ActionEvent
).
This is how it looks when I run the above code.
Answered By - Abra
Answer Checked By - Terry (JavaFixing Volunteer)