JavaFX application window doesn't show when running code - java

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);
}
}

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.

Related

Is it possible to do a shuffle in this manner with a boolean instead of a list?

Here my code (In Java on Eclipse) displays 3 random cards from the a file. I am trying to get a shuffle button to work and randomly shuffle in 3 new cards. I used "Collections.shuffle(cards);" and passed it my boolean array but it says I can't because it wants a List<> list. Is it possible to get the shuffle to work with my boolean or would I have to use a List?
Here is my code:
import java.util.Collections;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DisplayCards extends Application {
HBox imageViews;
#Override
public void start(Stage primaryStage) throws Exception {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
boolean[] cards = new boolean[52];
int count = 0;
while(count <3) {
int card = (int)(Math.random() * 52);
if(!cards[card]) {
cards[card] = true;
pane.add(new ImageView(new Image("card/" + (card) + ".png")), count, 0);
count++;
}
}
imageViews = new HBox();
imageViews.setAlignment(Pos.CENTER);
shuffle();
Button btnShuffle = new Button("Shuffle");
btnShuffle.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
shuffle();
}
});
BorderPane Bpane = new BorderPane();
Bpane.setCenter(imageViews);
Bpane.setBottom(btnShuffle);
Scene scene = new Scene(pane, 250, 150);
primaryStage.setTitle("Display 4 Cards");
primaryStage.setScene(scene);
primaryStage.show();
}
private void shuffle() {
Collections.shuffle(cards);
}
public static void main(String[] args) {
launch(args);
}
}
You can implement the Fisher–Yates shuffle for an array.
private void shuffle(){
for(int i = cards.length - 1; i > 0; i--){
int j = java.util.concurrent.ThreadLocalRandom.current().nextInt(i + 1);
boolean temp = cards[i];
cards[i] = cards[j];
cards[j] = temp;
}
}

Program is crashing when I click on the start Button

I want to make a little game in JavaFX, but when I click on the start Button, Java(TM) Platform SE binary is crashing!
package sample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.effect.Bloom;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.Random;
public class Main extends Application {
#Override
public void start(Stage primaryStage){
Weiter weiter = new Weiter(true);
Random rand = new Random();
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setVgap(10);
grid.setHgap(10);
grid.setPadding(new Insets(10, 10, 10,10));
Rectangle ra = new Rectangle(120, 120);
ra.setFill(Color.LIGHTBLUE);
ra.setStroke(Color.BLACK);
ra.setStrokeWidth(2);
ra.setEffect(new Bloom());
grid.add(ra, 1, 0);
Button start = new Button("start");
grid.add(start, 0, 3);
TextField feld = new TextField();
grid.add(feld, 1, 3);
Button btnBest = new Button("ok");
grid.add(btnBest, 3, 3);
start.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (weiter.getWeiter()){
int wiedhol = rand.nextInt(101);
while (wiedhol == 0){
wiedhol = rand.nextInt(101);
}
System.out.println(wiedhol);
for(int i = 0; i <= wiedhol; i++){
try {
ra.setFill(Color.BLUE);
Thread.sleep(1000);
ra.setFill(Color.LIGHTBLUE);
}catch(InterruptedException ie){}
}
}
}
});
primaryStage.setScene(new Scene(grid, 400, 300));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Class Weiter:
package sample;
public class Weiter {
private boolean weiter;
public Weiter(boolean wert){
this.weiter = wert;
}
public boolean getWeiter(){
return weiter;
}
public void setWeiter(boolean wert){
this.weiter = wert;
}
}
Actually when I press the start Button it should make a Random Number and the Rectangle is turning Blue until the random number is reached. then you have to enter the number you counted and when it's right you won.
It does not crash.
Notice this:
for(int i = 0; i <= wiedhol; i++){
try {
ra.setFill(Color.BLUE);
Thread.sleep(1000);
ra.setFill(Color.LIGHTBLUE);
}catch(InterruptedException ie){}
}
That thread.sleep() halts your program.

Listen to changes in array

I need some help if you can spare a few minutes.
I am in a bit of a pickle as I try to make this work.
I have a javaFX class like this
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class FoorballTeam extends Application {
int i1=0;
int i3=0;
String[] PlayerNames = new String[12];
int[] goals = new int[12];
#Override
public void start(Stage primaryStage) {
player[] playerData = new player[12];
Button btn = new Button();
btn.setText("add Player");
GridPane root = new GridPane();
root.add(btn,0,0);
int i2;
for (i2=0;i2<=11;i2++)
{playerData[i2]=new player();}
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
playerData[i3].player(root, i3);
i3++;
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public String[] getPlayerNames() {
return PlayerNames;
}
public void setPlayerNames(String[] PlayerNames) {
this.PlayerNames = PlayerNames;
}
public int[] getGoals() {
return goals;
}
public void setGoals(int[] goals) {
this.goals = goals;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and a second class named player like this
import javafx.event.EventType;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
public class player {
String NameOfPlayer = new String();
int goalsOfPlayer;
public void player (GridPane root,int numberOfPlayer)
{
TextField name = new TextField();
TextField goals = new TextField();
GridPane grid = new GridPane();
grid.add(name,0,0);
grid.add(goals,1,0);
root.add(grid,0,numberOfPlayer+1);
System.out.println("player " + numberOfPlayer + " added");
name.textProperty().addListener((observable, oldValue, newValue) -> {
NameOfPlayer=newValue;
});
goals.textProperty().addListener((observable, oldValue, newValue) -> {
goalsOfPlayer=Integer.parseInt(newValue);
});
}
}
I want every time that I make a change to a players name or goals to pass this change on the two arrays PlayerNames[] and goals[] of the main class.
for example if player1 changes goals from 1 to 2 I want the goals[1]=2.
Also is it possible to put a listener to this two arrays so when a player changes name or goals to trigger the listener.
Any help will be appreciated.
One simple solution is to warp the int[] array with an observable list, and listen to changes in this list :
import java.util.Arrays;
import java.util.Random;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class ListenToArrayCahnges extends Application {
private final int SIZE = 12;
private final Integer[] goals = new Integer[SIZE];
private final Random rand = new Random();
private int counter = 0;
#Override
public void start(Stage primaryStage) {
Arrays.fill(goals, 0); //initial values
//Warp array with an observable list. list back by array so it is of fixed length
ObservableList<Integer> goalsList = FXCollections.observableArrayList(Arrays.asList(goals));
//add listener to list
goalsList.addListener((ListChangeListener<Integer>) c ->{
//respond to list changes
System.out.println("Goals changed to : "+ goalsList);
});
//button to change the list
Button btn = new Button();
btn.setText("Add goal");
btn.setOnAction(event -> {
goalsList.set(counter, rand.nextInt(100));
counter = ++counter % SIZE ; //increment counter 0,1,2....11 and back to 0
});
GridPane root = new GridPane();
root.add(btn,0,0);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Note that the posted mcve represents the problem that needs to be solved (or in this case a solution to it), and not the specific application or use case.

How to use jfxtra Magnifier and draw Rectangle on ImageView at the same time?

I'm trying to use the Magnifier from jfxtras-labs 2.2 to see more details on an image. At the same time, I want to draw a rectangle on top of this image. The problem is, that the Magnifier blocks all other events.
Here is my sample code:
package magnifiertest;
import java.io.File;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.Magnifier;
public class TestMagnifier extends Application {
Group groupForRectangles;
ImageView pageImageView;
private boolean new_rectangle_is_being_drawn;
private Rectangle new_rectangle;
private double starting_point_x;
private double starting_point_y;
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
groupForRectangles = new Group();
groupForRectangles = new Group();
pageImageView = new ImageView();
pageImageView.setPreserveRatio(true);
pageImageView.setFitHeight(800);
pageImageView.setFitWidth(600);
pageImageView.setImage(SwingFXUtils.toFXImage(ImageIO.read(new File("/sample/Penguins.jpg")), null));
groupForRectangles.setOnMouseDragged(event -> {
setOnMouseDragged(event);
});
groupForRectangles.setOnMousePressed(event -> {
setOnMousePressed(event);
});
groupForRectangles.setOnMouseReleased(event -> {
setOnMouseReleased(event);
});
//If you outcomment the following lines, the rectangle drawing works
Magnifier m = new Magnifier(pageImageView);
groupForRectangles.getChildren().add(pageImageView);
groupForRectangles.getChildren().add(m);
root.getChildren().add(groupForRectangles);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public void setOnMousePressed(MouseEvent event) {
System.out.println("mouse pressed");
if (new_rectangle_is_being_drawn == false) {
starting_point_x = event.getX();
starting_point_y = event.getY();
System.out.println(starting_point_x + " ; " + starting_point_y);
groupForRectangles.getChildren().remove(new_rectangle);
new_rectangle = new Rectangle();
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle.setStroke(Color.BLACK);
groupForRectangles.getChildren().add(new_rectangle);
new_rectangle_is_being_drawn = true;
}
}
public void setOnMouseDragged(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
double current_ending_point_x = event.getX();// - sub.getLayoutX();
double current_ending_point_y = event.getY();// - sub.getLayoutY();
adjust_rectangle_properties(starting_point_x, starting_point_y, current_ending_point_x,
current_ending_point_y, new_rectangle);
}
}
public void setOnMouseReleased(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle_is_being_drawn = false;
}
}
void adjust_rectangle_properties(double starting_point_x, double starting_point_y, double ending_point_x,
double ending_point_y, Rectangle given_rectangle) {
given_rectangle.setX(starting_point_x);
given_rectangle.setY(starting_point_y);
given_rectangle.setWidth((ending_point_x - starting_point_x));
given_rectangle.setHeight((ending_point_y - starting_point_y));
if (given_rectangle.getWidth() < 0) {
given_rectangle.setWidth(-given_rectangle.getWidth());
given_rectangle.setX(given_rectangle.getX() - given_rectangle.getWidth());
}
if (given_rectangle.getHeight() < 0) {
given_rectangle.setHeight(-given_rectangle.getHeight());
given_rectangle.setY(given_rectangle.getY() -
given_rectangle.getHeight());
}
}
}
Thanks.

javafx adding button to grid pane

I am adding button to grid pane dynamically but after giving them function they all show same function and i don't knows why?
import java.awt.Panel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
public class TestController implements Initializable {
#FXML
Panel mpanel;
#FXML
GridPane gpnael;
int x=0,y=0,i=0,y1=0;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void add(ActionEvent event) {
y1++;
Button temp = new Button("Button " + i);
temp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println("button"+y1);
}
});
gpnael.add(temp,i++,1);
}
}
now i have added three button to grid pane when i click on each button they show same output.
I want that they all show different output as assigned .
You are not defining it in the buttons, you are always using a non final int to express your values you should try do make them with unique values or to set an id for each button and get the value from the id:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ButtonsOnGPanel extends Application {
private int i = 0;
private GridPane gpnael = new GridPane();
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
while(i<3){
addButton();
}
root.getChildren().add(gpnael);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void addButton() {
i++;
final Button temp = new Button("Button " + i);
final int numButton= i;
temp.setId("" + i);
temp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println("id(" + temp.getId() + ") = " + numButton);
}
});
gpnael.add(temp, i, 1);
}
public static void main(String[] args) {
launch(args);
}
}
And if you want to use lambda expressions:
temp.setOnAction((ActionEvent e) -> {
System.out.println("id(" + temp.getId() + ") = " + numButton);
});

Categories