gridpane javafx clickable cells that get toggled and untoggled - javafx

I am trying to create a gridpane that is toggled/untoggled as the user clicks on specific cells. For example, when the user clicks on a cell with the content "*", I would like the content of that specific cell to be changed into a blank cell " ". Similarly, if the user clicks on a cell with a blank content " ", I would like the content of that cell to be changed into a cell with the content "*".
Basically, I am starting out with a grid that is partly input as follows:
My gridpane is initially input as follows, I am keeping track of a matrix of booleans that represents whether there should be a "*" in one cell of the matrix. If there is a "*" in cell [i, j] of the gridpane, then the value of matrix[i,j] should be true, otherwise it should be false.
boolean matrix[][] = new boolean[StateList.size()+1][RequirementList.size()+1];
for( InstanceArtifact li: ListOfLinks) {
int y=1;
for(InstanceArtifact re: RequirementList) {
int x=1;
for(InstanceArtifact state: StateList) {
if(li.getPropertyValue("linksource").equals(re) && li.getPropertyValue("linktarget").equals(state)) {
link= new Label(" * ");
//tick in cell (1,1)
grid.add(link, y, x);
matrix[x][y]= true;
}
else {
link= new Label(" ");
//tick in cell (1,1)
grid.add(link, y, x);
}
x++;
}
y++;
}
}
}
What I would like to do is toggle/untoggle the stars, this is what I am trying to do with the code below, as we are clicking on a cell containing "*", meaning that matrix[i][j]=true, I am removing the corresponding label in the grid and I am adding a new label with an empty text. I also do the same thing in the opposite situation in which the label text is blank and I need to replace it with a label containing a star.
grid.getChildren().forEach(element -> {
element.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
int matrixX= GridPane.getRowIndex(element);
int matrixY= GridPane.getColumnIndex(element);
if(element!=null && matrixX!=0 && matrixY!=0) {
System.out.println("matrixX: "+matrixX+" matrixY: "+matrixY);
System.out.println("matrixY: "+matrixY+" "+ matrix[matrixX][matrixY]);
if(matrix[matrixX][matrixY]==true && matrixX!=0 && matrixY!=0) {
System.out.println("HEY I AM HERE FIRSTTTTTTTTT");
Node newnode= new Label(" ");
GridPane.clearConstraints(element);
// grid.getChildren().remove(element);
grid.add(newnode, matrixY, matrixX);
matrix[matrixX][matrixY]=false;
/*for(int l=0; l<RequirementList.size(); l++) {
for(int p=0; p<StateList.size(); p++) {
System.out.println(l + " "+p +" "+matrix[l][p]);
}
}*/
//grid.add(mynode, matrixY+1, matrixX+1, 1, 1);
}
else if(matrix[matrixX][matrixY]==false && matrixX!=0 && matrixY!=0){
System.out.println("HEY I AM HERE SECONDDDDDDD ");
/* for(int l=0; l<RequirementList.size(); l++) {
for(int p=0; p<StateList.size(); p++) {
System.out.println(l + " "+p +" "+matrix[l][p]);
}
}*/
Node falsenode= new Label(" * ");
GridPane.clearConstraints(element);
// grid.getChildren().remove(element);
grid.add(falsenode, matrixY, matrixX);
matrix[matrixX][matrixY]=true;
}
// System.out.println("Row: " + GridPane.getRowIndex(element));
// System.out.println("Column: " + GridPane.getColumnIndex(element));
}
}
});
});
My code is not behaving as expected, I would like the cell to be toggled/untoggled whenever the user clicks on a cell, the code is executed only the first time the user clicks on a given cell, if the user clicks on the same cell multiple times (more than once), then nothing happens.
Also, the line of code in which I am trying to remove a label is not working:
grid.getChildren().remove(element);

This could be better served with ToggleButton. Comments in code.
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/**
*
* #author Sedrick
*/
public class JavaFXApplication60 extends Application {
#Override
public void start(Stage primaryStage) {
//Start create GUI
Label lblRequirement11 = new Label("Requirement1");
Label lblRequirement12 = new Label("Requirement2");
Label lblRequirement13 = new Label("Requirement3");
GridPane.setConstraints(lblRequirement11, 1, 0);
GridPane.setConstraints(lblRequirement12, 2, 0);
GridPane.setConstraints(lblRequirement13, 3, 0);
Label lblState1 = new Label("State1");
ToggleButton toggleButton11 = new ToggleButton();
toggleButton11.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton12 = new ToggleButton();
toggleButton12.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton13 = new ToggleButton();
toggleButton13.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState1, 0, 1);
GridPane.setConstraints(toggleButton11, 1, 1);
GridPane.setConstraints(toggleButton12, 2, 1);
GridPane.setConstraints(toggleButton13, 3, 1);
Label lblState2 = new Label("State2");
ToggleButton toggleButton21 = new ToggleButton();
toggleButton21.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton22 = new ToggleButton();
toggleButton22.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton23 = new ToggleButton();
toggleButton23.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState2, 0, 2);
GridPane.setConstraints(toggleButton21, 1, 2);
GridPane.setConstraints(toggleButton22, 2, 2);
GridPane.setConstraints(toggleButton23, 3, 2);
Label lblState3 = new Label("State3");
ToggleButton toggleButton31 = new ToggleButton();
toggleButton31.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton32 = new ToggleButton();
toggleButton32.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton33 = new ToggleButton();
toggleButton33.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState3, 0, 3);
GridPane.setConstraints(toggleButton31, 1, 3);
GridPane.setConstraints(toggleButton32, 2, 3);
GridPane.setConstraints(toggleButton33, 3, 3);
GridPane root = new GridPane();
root.setVgap(5);
root.setHgap(5);
root.getChildren().addAll(lblRequirement11, lblRequirement12, lblRequirement13);
root.getChildren().addAll(lblState1, toggleButton11, toggleButton12, toggleButton13);
root.getChildren().addAll(lblState2, toggleButton21, toggleButton22, toggleButton23);
root.getChildren().addAll(lblState3, toggleButton31, toggleButton32, toggleButton33);
//End create GUI
//Start create ToggleButtons' event handlers.
List<ToggleButton> toggleButtonList = new ArrayList();
toggleButtonList.add(toggleButton11);
toggleButtonList.add(toggleButton12);
toggleButtonList.add(toggleButton13);
toggleButtonList.add(toggleButton21);
toggleButtonList.add(toggleButton22);
toggleButtonList.add(toggleButton23);
toggleButtonList.add(toggleButton31);
toggleButtonList.add(toggleButton32);
toggleButtonList.add(toggleButton33);
for(ToggleButton tempToggleButton : toggleButtonList)
{
tempToggleButton.setOnAction(actionEvent -> {
if(tempToggleButton.isSelected())
{
tempToggleButton.setText("*");
}
else
{
tempToggleButton.setText("");
}
});
}
////End create ToggleButtons' event handlers.
Scene scene = new Scene(root, 400, 300);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX - Check the position of a label based on a mouse click

I try to write a code that find the label on which one have clicked.
Using an event listener, I got the positions of the event using getX() and getY().
However, I cannot find the adequate methods for the label positions in order to compare them.
Below is my code, and its ouput.
public class Beta extends Application {
final Label[] answerLabel = new Label[4];
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 7 ;
final int numRows = 12 ;
//final Label[] answerLabel = new Label[4];
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
for(int i = 0; i<4; i++){
answerLabel[i] = new Label();
answerLabel[i].setMaxWidth(Double.MAX_VALUE);
answerLabel[i].setMaxHeight(Double.MAX_VALUE);
answerLabel[i].setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
answerLabel[i].setPadding(new Insets(10));
answerLabel[i].setCursor(Cursor.HAND);
root.add(answerLabel[i], 3, i +5, 1, 1);
answerLabel[i].setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
answerLabelPressed(e);
}
});
}
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
private void answerLabelPressed(MouseEvent e)
{
int labelSelected;
double px = e.getX();
double py = e.getY();
System.out.println("px = " + px + " py = " + py);
for (labelSelected = 0; labelSelected < 4; labelSelected++)
{
System.out.println("answerLabel[labelSelected].getLayoutX() = " + answerLabel[labelSelected].getLayoutX());
System.out.println("answerLabel[labelSelected].getLayoutY() = " + answerLabel[labelSelected].getLayoutY());
}
}
public static void main(String[] args) {
launch(args);
}
}
px = 42.0 py = 7.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 208.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 250.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 292.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 333.0
Upadate: The main purpose was to find/check the equivalent JavaFX methods of those used in Java Swing.
An alternative and better algorithm beeing as one can read in most popular Java books :
MouseListener ml = new MouseListener() {
public void mouseClicked(MouseEvent e) {
report("mouseClicked", e.paramString());
}
In Java Swing, one should read :
Point p = e.getComponent().getLocation();
System.out.println("px = " + p.getX() + " py = " + p.getY());
for (labelSelected = 0; labelSelected < 4; labelSelected++)
{
System.out.println("answerLabel[labelSelected].getX() = " + answerLabel[labelSelected].getX());
System.out.println("answerLabel[labelSelected].getY() = " + answerLabel[labelSelected].getY());
}
I try to write a code that find the label on which one have clicked.
You create four labels, and you create a listener for each label. Each listener is only registered with one label.
So there is no need to get your hands dirty with the coordinates of the click (the event handling mechanism has already done all of that for you, when it decided to which node to dispatch the event). Just reference the label that was clicked:
public class Beta extends Application {
final Label[] answerLabel = new Label[4];
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 7 ;
final int numRows = 12 ;
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
for(int i = 0; i<4; i++){
answerLabel[i] = new Label();
answerLabel[i].setMaxWidth(Double.MAX_VALUE);
answerLabel[i].setMaxHeight(Double.MAX_VALUE);
answerLabel[i].setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
answerLabel[i].setPadding(new Insets(10));
answerLabel[i].setCursor(Cursor.HAND);
root.add(answerLabel[i], 3, i +5, 1, 1);
Label currentLabel = answerLabel[i];
int currentIndex = i ;
answerLabel[i].setOnMouseClicked(event -> {
System.out.println("Clicked on label "+currentIndex);
// just for demo: in real life use external stylesheets
// and pseudoclasses, etc.
for (Label label : answerLabel) {
label.setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
}
currentLabel.setStyle("-fx-background-color: gold;-fx-font-size: 7pt;-fx-padding: 0;");
});
}
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
}
It is not necessary to manually compute which node the mouse clicked on. That calculation is already done for you by the framework. That's how the framework knows which event handlers to invoke. If you simply add a unique handler to each node, then when that handler is invoked only that node could be the source. This is demonstrated in #James_D's answer.
However, if you want to manually compute which node was clicked (e.g., for fun or just for learning purposes), then here is a runnable example:
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Border;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var labels = IntStream.range(0, 12)
.mapToObj(this::createLabel)
.toArray(Label[]::new);
var grid = new GridPane();
grid.setPadding(new Insets(20));
grid.setHgap(20);
grid.setVgap(20);
grid.setOnMouseClicked(e -> {
var clickedOnLabel = getClickedOnLabel(labels, e);
if (clickedOnLabel == null) {
System.out.println("You did not click on a label!");
} else {
System.out.printf("You clicked on a label: '%s'%n", clickedOnLabel.getText());
}
});
int i = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 3; row++) {
grid.add(labels[i++], col, row);
}
}
primaryStage.setScene(new Scene(grid));
primaryStage.show();
}
private Label getClickedOnLabel(Label[] labels, MouseEvent event) {
for (var label : labels) {
var bounds = label.localToScene(label.getBoundsInLocal());
if (bounds.contains(event.getSceneX(), event.getSceneY())) {
return label;
}
}
return null;
}
private Label createLabel(int n) {
var label = new Label(String.format("Label #%02d", n));
label.setCursor(Cursor.HAND);
label.setPadding(new Insets(5));
label.setFont(Font.font("Monospaced", 15.0));
label.setBorder(Border.stroke(Color.BLACK));
return label;
}
}
The important part, the part which computes which label was clicked on, is here:
private Label getClickedOnLabel(Label[] labels, MouseEvent event) {
for (var label : labels) {
var bounds = label.localToScene(label.getBoundsInLocal());
if (bounds.contains(event.getSceneX(), event.getSceneY())) {
return label;
}
}
return null;
}
It gets the bounds of each Label in the scene's coordinate space, and then tests if the mouse's location—also in the scene's coordinate space—is contained within those bounds. You can use whatever coordinate space you like (e.g., the screen's, the grid pane's, the label's, etc.), as long as you use the same one for both the label's bounds and the mouse's location. Note the mouse's local coordinates (i.e., getX() and getY()) are in the source node's coordinate space. The source node is the node that the currently-being-invoked handler was registered with for the specific event currently being processed (the GridPane in the above example).
But again, for any "real" code, I strongly recommend you use the solution in #James_D's answer.

Is there a condition where a node in a javaFX scene will not be shown?

I decided to create a JavaFX calculator that includes Buttons and Labels and a Pane as my root Parent.
I'm still stuck with the layout, here is a rough sketch of the expected result:
Bear with my poor graphics.
The problem is that I see a blank screen when I run the following code:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.text.*;
import javafx.scene.paint.Color;
import javafx.geometry.Pos;
/**
* This class is meant to serve as a simple calculator with basic funtions
* to try myself out with javafx
*/
public class CalculatorFX extends Application{
Label question; // This is the label that shows the question
Label answer; // This is the label that shows the answer
Button[] buttons = new Button[19]; // This is the buttons of the calculator
/**
* This is the root parent or container. It is defined out here because
* I hope to know its length and width are crucial for the layout.
*/
Pane root = new Pane();
/**
* This is the length of the Pane
*/
double rootHeight = root.getHeight();
/**
* This is the width of the Pane
*/
double rootWidth = root.getWidth();
public static void main(String[] args){
launch(args);
}
/**
* This start routine sets up the GUI
*/
public void start(Stage stage){
question = new Label("Type your question");
answer = new Label("Answer:");
question.setTextFill(Color.BLACK);
question.setFont( Font.font(null, FontWeight.BOLD, 18) );
question.setStyle("-fx-font: 15pt sans-serif; -fx-padding: 7px; -fx-border-color: darkred; -fx-border-width: 2px; -fx-text-fill: darkred; -fx-background-color: pink; ");
/* Initializing the numerical buttons first using a loop */
// for(int i = 0; i < 10; i++){
// buttons[i] = new Button(i + "");
// }
/* They are configured like this in the way, they would appear on
* the parent node */
buttons[0] = new Button("CLEAR");
buttons[1] = new Button("DEL");
buttons[2] = new Button("CONT");
buttons[3] = new Button("7");
buttons[4] = new Button("8");
buttons[5] = new Button("9");
buttons[6] = new Button("*");
buttons[7] = new Button("4");
buttons[8] = new Button("5");
buttons[9] = new Button("6");
buttons[10] = new Button("/");
buttons[11] = new Button("1");
buttons[12] = new Button("2");
buttons[13] = new Button("3");
buttons[14] = new Button("-");
buttons[15] = new Button("0");
buttons[16] = new Button(".");
buttons[17] = new Button("=");
buttons[18] = new Button("+");
/* Here we set the position of the children */
double unitX = rootWidth/4;
double unitY = rootHeight/9;
double nextX = rootWidth;
double nextY = rootHeight;
for(int lineNum = 6; lineNum >= 0; lineNum--){
nextY = nextY - unitY;
nextX = rootWidth - unitX;
for(int element = 4; element >=0 ; element--){
if(lineNum == 1){// Then we need to fill the lines
if( element == 1)
continue;
//buttons[lineNum + element + 8].relocate(nextX, nextY);
}
if(lineNum == 0){
answer.relocate(0, nextY - unitY);
System.out.println("Relocated answer label");
question.relocate(0,0);
System.out.println("Relocated answer label");
break; // This breaks out of two for loops because
// this is the last lineNum.
}
//buttons[lineNum + element + 8].relocate(nextX, nextY);
nextX = nextX - unitX;
}
}
/* There is also a need to resize the children */
question.setManaged(false);
question.resize(rootWidth, 2*unitY);
System.out.println("Resized label question");
answer.setManaged(false);
answer.resize(rootWidth, 2*unitY);
System.out.println("Resized label answer");
// for(int i = 0; i < buttons.length; i++){
// buttons[i].setManaged(false);
// buttons[i].resize(unitX, unitY);
// }
/* Time to configure them on our root */
root.setPrefWidth(400);
root.setPrefHeight(800);
root.getChildren().addAll(question, answer);
// for(int i = 0; i < buttons.length; i++){
// root.getChildren().add(buttons[i]);
// }
Scene scene = new Scene(root);
scene.getStylesheets().add("myStyle.css");
stage.setScene(scene);
stage.setTitle("CalculatorFX");
stage.show();
} // End of start
} // End of class CalculatorFX
Now, myStyle.css contains:
Button {
-fx-font: bold 16pt "Times New Roman";
-fx-text-fill: darkblue;
}
Label {
-fx-font: 15pt sans-serif;
-fx-padding: 7px;
-fx-border-color: darkred;
-fx-border-width: 2px;
-fx-text-fill: darkred;
-fx-background-color: pink;
}
Help me. Why do I see a blank screen?
To answer your main question:
Yes there is!
In JavaFX, Nodes have visible property:
Specifies whether this Node and any subnodes should be rendered as part of the scene graph.
You control it using the setVisible method.
To help you get started:
As Zephyr and Jamed_D pointed out, you are doing too much work.
I believe there are several correct ways to go about what you are trying to achieve.
A visual editor like SceneBuilder comes to mind. It could help you get a deeper understanding of JavaFX's components. Especially, if building the GUI programmatically is not a must for you.
Here is a simple example to help you get started with one of the ways:
public class App extends Application {
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage stage) {
var label1 = new Label("Type your question: ");
var label2 = new Label("Answer: ");
label1.setPrefHeight(40);
label2.setPrefHeight(40);
label1.setPadding(new Insets(0, 10, 0, 10));
label2.setPadding(new Insets(0, 10, 0, 10));
HBox label1HB = new HBox(label1);
HBox label2HB = new HBox(label2);
VBox vBox = new VBox();
vBox.setFillWidth(true);
vBox.setPrefWidth(Double.MAX_VALUE);
vBox.setPrefHeight(Double.MAX_VALUE);
vBox.getChildren().addAll(label1HB, label2HB);
List<HBox> rows = new ArrayList<>();
for (int row = 0; row < 6; row++) {
HBox hbox = new HBox();
for (int col = 0; col < 4; col++) {
Button button = new Button(row + " " + col);
button.setMaxWidth(Double.MAX_VALUE);
button.setMaxHeight(Double.MAX_VALUE);
HBox.setHgrow(button, Priority.ALWAYS);
hbox.getChildren().add(button);
}
VBox.setVgrow(hbox, Priority.ALWAYS);
rows.add(hbox);
}
vBox.getChildren().addAll(rows);
// Uncomment the following line to see the visible property in action.
// rows.get(2).setVisible(false);
var scene = new Scene(vBox, 400, 800);
stage.setScene(scene);
stage.show();
}
}
I personally like wrapping my nodes within a VBox or an Hbox because it allows me to change the scene's size without worrying about resizing everything again.
You can find many tutorials online explaining how to exploit different JavaFX layouts' properties to achieve better as well as cleaner GUI and code.
It should be mentioned that you are going to have to take care of:
A couple of issues, like what happens when the window is too small to fit your entire content?
Some specifics, like if you want some of your nodes to have a fixed width and height.
etc.

When i run my program my thread is working but images are not setting for the grid can someone give a solution for this.

ISymbol interface
package main;
import javafx.scene.image.Image;
public interface ISymbol {
void setImage(String location,String name);
Image getImage();
void setValue(int value);
int getValue();
}
Symbol class
package main;
import javafx.scene.image.Image;
import java.io.File;
public class Symbol implements ISymbol {
Image image;
int value;
#Override
public void setImage(String location,String name) {
File file = new File(location);
image = new Image(file.toURI().toString(),100,100,true,true);
}
#Override
public Image getImage() {
return image;
}
#Override
public void setValue(int value) {
this.value = value;
}
#Override
public int getValue() {
return value;
}
}
In here i'm trying to add images randomly to a array and i'm using that array in my main class to add those images to my reels
Reel class
package main;
import java.util.Random;
public class Reel {
public Symbol[] spin(){
Symbol cherry = new Symbol();
Symbol redSeven = new Symbol();
Symbol watermelon = new Symbol();
Symbol bell = new Symbol();
Symbol lemon = new Symbol();
Symbol plum = new Symbol();
Random random = new Random();
Symbol[] symbolArray = new Symbol[6];
for (int i = 0; i < symbolArray.length; i++) {
int randomNumber = random.nextInt(6);
System.out.println(randomNumber);
switch (randomNumber) {
case 0:
cherry.setValue(2);
cherry.setImage("/images/cherry.png","cherry");
symbolArray[i] = cherry;
break;
case 1:
lemon.setValue(3);
lemon.setImage("/images/lemon.png","lemon");
symbolArray[i] = lemon;
break;
case 2:
plum.setValue(4);
plum.setImage("/images/plum.png","plum");
symbolArray[i] = plum;
break;
case 3:
watermelon.setValue(5);
watermelon.setImage("/images/watermelon.png", "watermelon");
symbolArray[i] = watermelon;
break;
case 4:
bell.setValue(6);
bell.setImage("/images/bell.png", "bell");
symbolArray[i] = bell;
break;
case 5:
redSeven.setValue(7);
redSeven.setImage("images/redseven.png","seven");
symbolArray[i] = redSeven;
break;
default:
break;
}
}
return symbolArray;
}
}
This is my main class that include all methods. In the btnSpin method i'm calling my thread and for setting images for the reels i have used a reel method
I have debug my program and checked whether the image is coming the image was on there but when i set my image to the image view it wont work while i'm running my thread those imageviews are disappeared can someone give me a solution waiting for a reply thank you :)
SlotMachine class
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.effect.Reflection;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import main.Reel;
import main.Symbol;
public class SlotMachine extends Application implements Runnable {
//creating a thread
Thread thread1 = new Thread(){
#Override public void run(){
reel1();
}
};
//default image for reel
private Image image = new Image("/images/icon.png");
//UI variables
private Text title;
private Label lblStatus,lblInformationArea, lblBetAmount, lblCreditArea;
private ImageView image1, image2, image3;
private Button btnSpin, btnAddCoin, btnBetOne, btnBetMax, btnReset, btnStatistics;
//calculation variables
private int remainingCoins = 10;
private int betAmount, wins, lost, reel1value, reel2value, reel3value;
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 0, 10, 0));
grid.setHgap(20);
grid.setVgap(20);
grid.setGridLinesVisible(true);
// Title in row 0 column 3 with styling
title = new Text();
title.setCache(true);
title.setText("REEL RUSH");
title.setFill(Color.YELLOW);
title.setFont(Font.font("Arial", FontWeight.BOLD, 60));
Reflection r = new Reflection();
title.setEffect(r);
GridPane.setConstraints(title, 3, 1);
GridPane.setHalignment(title, HPos.CENTER);
// Reel1 in row 4 column 2
image1 = new ImageView(image);
GridPane.setConstraints(image1, 2, 4);
GridPane.setHalignment(image1, HPos.CENTER);
// Reel2 in row 4 column 3
image2 = new ImageView(image);
GridPane.setConstraints(image2, 3, 4);
GridPane.setHalignment(image2, HPos.CENTER);
// Reel3 in row 4 column 4
image3 = new ImageView(image);
GridPane.setConstraints(image3, 4, 4);
GridPane.setHalignment(image3, HPos.CENTER);
// adding mouse click event for image views
image1.setOnMouseClicked(new EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(javafx.scene.input.MouseEvent event) {
symbolClicked(event);
System.out.println("REEL 1 IS CLICKED");
}
});
image2.setOnMouseClicked(new EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(javafx.scene.input.MouseEvent event) {
symbolClicked(event);
System.out.println("REEL 2 IS CLICKED");
}
});
image3.setOnMouseClicked(new EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(javafx.scene.input.MouseEvent event) {
symbolClicked(event);
System.out.println("REEL 3 IS CLICKED");
}
});
// Status label row 8 column 4
lblStatus = new Label("YOU LOOSE");
lblStatus.setId("label-lblStatus");
GridPane.setConstraints(lblStatus, 3, 8);
GridPane.setHalignment(lblStatus, HPos.CENTER);
//information area label row 9 column 3
lblInformationArea = new Label("INFORMATION AREA ");
lblInformationArea.setId("label-lbl");
GridPane.setConstraints(lblInformationArea, 3, 9);
GridPane.setHalignment(lblInformationArea, HPos.CENTER);
// Credit area label row 5 column 2
lblCreditArea = new Label("CREDIT AREA: " + remainingCoins);
lblCreditArea.setId("label-lbl");
GridPane.setConstraints(lblCreditArea, 2, 9);
GridPane.setHalignment(lblCreditArea, HPos.CENTER);
// Bet amount label row 5 column 4
lblBetAmount = new Label("BET AMOUNT: " +betAmount);
lblBetAmount.setId("label-lbl");
GridPane.setConstraints(lblBetAmount, 4, 9);
GridPane.setHalignment(lblBetAmount, HPos.CENTER);
// Add coin button row 6 column 3
btnSpin = new Button("SPIN");
btnSpin.setId("button-btnSpin");
GridPane.setConstraints(btnSpin, 3, 10);
GridPane.setHalignment(btnSpin, HPos.CENTER);
// Add coin button row 8 column 1
btnAddCoin = new Button("ADD COIN");
GridPane.setConstraints(btnAddCoin, 2, 12);
GridPane.setHalignment(btnAddCoin, HPos.CENTER);
// Add coin button row 8 column 2
btnBetOne = new Button("BET ONE");
btnBetOne.setFont(Font.font("Arial", 20));
GridPane.setConstraints(btnBetOne, 1, 12);
GridPane.setHalignment(btnBetOne, HPos.CENTER);
// Add coin button row 8 column 3
btnBetMax = new Button("BET MAX");
GridPane.setConstraints(btnBetMax, 4, 12);
GridPane.setHalignment(btnBetMax, HPos.CENTER);
// Add coin button row 8 column 4
btnReset = new Button("RESET");
GridPane.setConstraints(btnReset, 6, 12);
GridPane.setHalignment(btnReset, HPos.CENTER);
// Add coin button row 8 column 5
btnStatistics = new Button("STATISTICS");
GridPane.setConstraints(btnStatistics, 3, 12);
GridPane.setHalignment(btnStatistics, HPos.CENTER);
// ------------------- Adding mouse events for each button ---------------------------
btnAddCoin.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
remainingCoins++;
lblCreditArea.setText("CREDIT AREA: "+remainingCoins);
}
});
btnBetOne.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
if (remainingCoins > 0) {
remainingCoins--;
betAmount++;
lblBetAmount.setText("BET AMOUNT: " + betAmount);
lblCreditArea.setText("CREDIT AREA: " + remainingCoins);
} else {
lblInformationArea.setText("No Credits Left!!!! Please Insert A Coin");
}
}
});
btnSpin.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
if (betAmount > 0) {
System.out.println("SPIN BUTTON CLICKED");
thread1.start();
} else {
lblInformationArea.setText("You did not bet!!!! Please Bet");
}
}
});
btnReset.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
remainingCoins = 10;
betAmount = 0;
lblBetAmount.setText("BET AMOUNT: " + betAmount);
lblCreditArea.setText("CREDIT AREA: " + remainingCoins);
lblInformationArea.setText("Status");
image1.setImage(image);
image2.setImage(image);
image3.setImage(image);
}
});
btnBetMax.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
if (remainingCoins >= 3) {
remainingCoins = remainingCoins - 3;
betAmount = betAmount + 3;
lblBetAmount.setText("BET AMOUNT: " + betAmount);
lblCreditArea.setText("CREDIT AREA: " + remainingCoins);
} else {
lblInformationArea.setText("No Credits Left!!!! Please Insert A Coin");
}
}
});
btnStatistics.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
//statistic();
lblInformationArea.setText("Spin the Reel First");
}
});
// adding all to the scene
grid.getChildren().addAll(title, lblStatus, lblInformationArea, lblCreditArea, lblBetAmount, btnAddCoin, btnBetMax, btnBetOne, btnReset, btnSpin, btnStatistics, image1, image3 , image2);
grid.setAlignment(Pos.TOP_CENTER);
Scene scene = new Scene(grid, 1450, 920);
scene.getStylesheets().add("/css/main.css");
primaryStage.setTitle("REEL RUSH");
primaryStage.setScene(scene);
primaryStage.show();
}
public void reel1() {
while (true) {
//creating reel objects for each reel
Reel firstReel = new Reel();
Reel secondReel = new Reel();
Reel thirdReel = new Reel();
Symbol[] firstReelSymbols = firstReel.spin();
Symbol[] secondReelSymbols = secondReel.spin();
Symbol[] thirdReelSymbols = thirdReel.spin();
for (Symbol item : firstReelSymbols) {
Image img1 = item.getImage();
image1.setImage(img1);
reel1value = item.getValue();
}
for (Symbol item : secondReelSymbols) {
Image img1 = item.getImage();
image2.setImage(img1);
reel1value = item.getValue();
}
for (Symbol item : thirdReelSymbols) {
Image img1 = item.getImage();
image3.setImage(img1);
reel1value = item.getValue();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void symbolClicked(javafx.scene.input.MouseEvent event) {
//TODO stop thread when image clicked
if((reel1value==reel3value)&&(reel2value==reel3value)){
//check if all 3 numbers are same
lblInformationArea.setText("You Win");
remainingCoins+=(betAmount*reel1value);
lblCreditArea.setText("Credits Area: "+remainingCoins);
wins++;
}else{
lblInformationArea.setText("You Loose");
lost++;
}
betAmount=0;
lblBetAmount.setText("Bet Amount: "+betAmount);
}
#Override
public void run() {
}
public static void main(String[] args){
launch(args);
}
}
Technically, while you can "run" an Application, we would never implement Runnable in an Application. JavaFX will do its own application management, and there is no way you can "run" an application in another thread.
Now, back to your question. Your reel1() is badly written. If you know a particular method is going to run in non-UI thread (i.e. JavaFX Application thread), you must take note not to directly set any kind of value that changes the UI within it.
So, this:
for (Symbol item : firstReelSymbols) {
Image img1 = item.getImage();
image1.setImage(img1);
reel1value = item.getValue();
}
should becomes something like:
for (Symbol item : firstReelSymbols) {
Image img1 = item.getImage();
Platform.runLater(() -> image1.setImage(img1)); // Run this run on UI thread
reel1value = item.getValue(); // Not sure what this value is for, may need to be wrapped inside Platform.runLater() if it affects UI
}
Other than this, it is weird that you are looping through a list of Symbol objects, and inside the loop you are setting the same image1 field.

Need help inserting buttons into Tic Tac Toe game

I have a tic tac toe game that is made for us but I have to insert a button or two so the user can select if they want to be an X or and O. Can you guys help me modify this code please? I am unsure of how to do this because every time I try to add something it doesn't compile. Your help is much appreciated.
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Ellipse;
public class TicTacToe extends Application {
private char whoseTurn = 'X';
private Cell[][] cell = new Cell[3][3];
private Label lblStatus = new Label("X's turn to play");
#Override
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
pane.add(cell[i][j] = new Cell(), j, i);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
borderPane.setBottom(lblStatus);
Scene scene = new Scene(borderPane, 550, 470);
primaryStage.setTitle("Wild TicTacToe");
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setResizable(false);
}
/** Determine if the cell are all occupied */
public boolean isFull() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (cell[i][j].getToken() == ' ')
return false;
return true;
}
/** Determine if the player with the specified token wins */
public boolean isWon(char token) {
for (int i = 0; i < 3; i++)
if (cell[i][0].getToken() == token
&& cell[i][1].getToken() == token
&& cell[i][2].getToken() == token) {
return true;
}
for (int j = 0; j < 3; j++)
if (cell[0][j].getToken() == token
&& cell[1][j].getToken() == token
&& cell[2][j].getToken() == token) {
return true;
}
if (cell[0][0].getToken() == token
&& cell[1][1].getToken() == token
&& cell[2][2].getToken() == token) {
return true;
}
if (cell[0][2].getToken() == token
&& cell[1][1].getToken() == token
&& cell[2][0].getToken() == token) {
return true;
}
return false;
}
public class Cell extends Pane {
private char token = ' ';
public Cell() {
setStyle("-fx-border-color: black");
this.setPrefSize(2000, 2000);
this.setOnMouseClicked(e -> handleMouseClick());
}
/** Return token */
public char getToken() {
return token;
}
/** Set a new token */
public void setToken(char c) {
token = c;
if (token == 'X') {
Line line1 = new Line(10, 10,
this.getWidth() - 10, this.getHeight() - 10);
line1.endXProperty().bind(this.widthProperty().subtract(10));
line1.endYProperty().bind(this.heightProperty().subtract(10));
Line line2 = new Line(10, this.getHeight() - 10,
this.getWidth() - 10, 10);
line2.startYProperty().bind(
this.heightProperty().subtract(10));
line2.endXProperty().bind(this.widthProperty().subtract(10));
// Add the lines to the pane
this.getChildren().addAll(line1, line2);
}
else if (token == 'O') {
Ellipse ellipse = new Ellipse(this.getWidth() / 2,
this.getHeight() / 2, this.getWidth() / 2 - 10,
this.getHeight() / 2 - 10);
ellipse.centerXProperty().bind(
this.widthProperty().divide(2));
ellipse.centerYProperty().bind(
this.heightProperty().divide(2));
ellipse.radiusXProperty().bind(
this.widthProperty().divide(2).subtract(10));
ellipse.radiusYProperty().bind(
this.heightProperty().divide(2).subtract(10));
ellipse.setStroke(Color.BLACK);
ellipse.setFill(Color.WHITE);
getChildren().add(ellipse); // Add the ellipse to the pane
}
}
/* Handle a mouse click event */
private void handleMouseClick() {
// If cell is empty and game is not over
if (token == ' ' && whoseTurn != ' ') {
setToken(whoseTurn); // Set token in the cell
// Check game status
if (isWon(whoseTurn)) {
lblStatus.setText(whoseTurn + " won! The game is over.");
whoseTurn = ' '; // Game is over
}
else if (isFull()) {
lblStatus.setText("Draw! The game is over.");
whoseTurn = ' '; // Game is over
}
else {
// Change the turn
whoseTurn = (whoseTurn == 'X') ? 'O' : 'X';
// Display whose turn
lblStatus.setText(whoseTurn + "'s turn.");
}
}
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Can't really see why adding a button would be a problem when you've already created this program using fairly advanced JavaFX code.
Just see the Button documentation on how to create a Button. Then add your button(s) to e.g. a HBox that you then add to your BorderPane:
Button xButton = new Button("X");
Button obutton = new Button("O");
HBox buttonBar = new HBox();
buttonBar.getChildren().addAll(xButton, oButton);
borderPane.setTop(buttonBar);
With that said. In your scenario, maybe a ToggleButton would be a better option. It allows the button to be selected, which would help in providing some visual feedback that O or X has been chosen properly.

Array size not setting correctly

I asked a previous question here, and got excellent feedback. I am back with one more issue in the same program. My output file is always blank, and I figured out why, but I don't know how to correct it. In getArray, I set totalEmployees to the value entered in the stage2 textField. This is supposed to be the array size declaration, but when i test the code, the array size is always set to 0, therefore giving me a blank text doc. This is because the array size is set to totalEmployees before the value is saved to totalEmployees. I am not quite sure how to go about correcting this. Here is the code that I have:
import java.io.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
public class companyParoll extends Application
{
private TextField tfNumOfEmployees = new TextField();
private TextField tfEmpFirstName = new TextField();
private TextField tfEmpLastName = new TextField();
private TextField tfEmpPayRate = new TextField();
private TextField tfEmpHoursWorked = new TextField();
private Button btEnterNum = new Button("Submit");
private Button btNextEmp = new Button("Add Employee");
private Button btRunReport = new Button("Run Report");
private Button btQuit = new Button("Quit");
//Declare Variables
int totalEmployees;
int index = 0;
String[] firstName = new String[totalEmployees];
String[] lastName = new String[totalEmployees];
double[] payRate = new double[totalEmployees];
double[] hoursWorked = new double[totalEmployees];
Stage stage2 = new Stage();
#Override // Override the start method in the Application class
public void start(Stage primaryStage)
{
//Create the UI
GridPane gridPane =new GridPane();
GridPane gridPane2 = new GridPane();
gridPane.setHgap(75);
gridPane.setVgap(15);
gridPane.add(new Label("Employee's First Name:"), 0, 0);
gridPane.add(tfEmpFirstName, 1, 0);
gridPane.add(new Label("Employee's Last Name:"), 0, 1);
gridPane.add(tfEmpLastName, 1, 1);
gridPane.add(new Label("Employee's Hourly Pay Rate:"), 0, 2);
gridPane.add(tfEmpPayRate, 1, 2);
gridPane.add(new Label("Hours Worked by Employee"), 0, 3);
gridPane.add(tfEmpHoursWorked, 1, 3);
gridPane.add(btNextEmp, 1, 4);
gridPane.add(btQuit, 0, 6);
gridPane.add(btRunReport, 1, 6);
//Set properties
gridPane.setAlignment(Pos.CENTER);
tfEmpFirstName.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpLastName.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpPayRate.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpHoursWorked.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btQuit, HPos.LEFT);
GridPane.setHalignment(btRunReport, HPos.RIGHT);
GridPane.setHalignment(btNextEmp, HPos.RIGHT);
gridPane2.setHgap(75);
gridPane2.setVgap(15);
gridPane2.add(new Label("Enter the Number of Employees:"), 0, 0);
gridPane2.add(tfNumOfEmployees,0 ,1);
gridPane2.add(btEnterNum, 0, 2);
gridPane2.setAlignment(Pos.CENTER);
tfNumOfEmployees.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btEnterNum, HPos.CENTER);
btEnterNum.setOnAction(e -> getArraySize());
btRunReport.setOnAction(e -> outputReport());
btNextEmp.setOnAction(e -> addEmployeeData());
btQuit.setOnAction(e -> quitApplication());
// Create a scene and place it in the stage
Scene scene= new Scene(gridPane, 400, 250) ;
primaryStage.setTitle("Payroll Calculator"); // Set title
primaryStage.setScene(scene); // Place the scene in t he stage
primaryStage.show(); // Display the stage
//Create new window to get number of employees
Scene scene2 = new Scene(gridPane2, 200, 150);
stage2.setTitle("Number of Employees");
stage2.setScene(scene2);
stage2.show();
}
public void getArraySize()
{
totalEmployees = Integer.parseInt(tfNumOfEmployees.getText());
stage2.close();
}
public void addEmployeeData()
{
while (index < firstName.length)
{
firstName[index] = tfEmpFirstName.getText();
lastName[index] = tfEmpLastName.getText();
payRate[index] = Double.parseDouble(tfEmpPayRate.getText());
hoursWorked[index] = Integer.parseInt(tfEmpHoursWorked.getText());
index ++;
break;
}
tfEmpFirstName.clear();
tfEmpLastName.clear();
tfEmpPayRate.clear();
tfEmpHoursWorked.clear();
}
public void outputReport()
{
try
{
PrintWriter empPayroll = new PrintWriter("Payroll.txt");
double regularHours = 0;
double overtimeHours = 0;
double regularPay = 0;
double overtimePay = 0;
double totalPay = 0;
for (index = 0; index < firstName.length; index++)
{
if (hoursWorked[index] >= 40)
regularHours = 40;
else
regularHours = hoursWorked[index];
if (hoursWorked[index] > 40)
overtimeHours = hoursWorked[index] - 40;
else
overtimeHours = 0;
regularPay = (payRate[index] * regularHours);
overtimePay = ((payRate[index] * 1.5) * overtimeHours);
totalPay = regularPay + overtimePay;
empPayroll.println("\nName: " + firstName[index] + " " + lastName[index]);
empPayroll.println("Pay Rate: " + payRate[index]);
empPayroll.println("Regular Hours Worked: " + regularHours);
empPayroll.println("Overtime Hours Worked: " + overtimeHours);
empPayroll.println("Regular Pay: " + regularPay);
empPayroll.println("Overtime Pay: " + overtimePay);
empPayroll.println("Total Gross Pay: " + totalPay);
}
empPayroll.close();
}
catch (IOException exp)
{
exp.printStackTrace();
}
System.out.println(firstName.length);
}
public void quitApplication()
{
Platform.exit(); //Close application
}
public static void main(String[] args)
{
Application.launch();
}
}
It looks like you're only using "totalEmployees" to instantiate those arrays.
Assuming that those arrays are not used anytime before the user clicks btEnterNum (Which is important because trying to do so would result in a Null Pointer Exception),
you could just declare the arrays, and instantiate them in your getArraySize() method.
private String[] firstName;
private String[] lastName;
private double[] payRate;
private double[] hoursWorked;
public void getArraySize() {
totalEmployees = Integer.parseInt(tfNumOfEmployees.getText());
firstName = new String[totalEmployees];
lastName = new String[totalEmployees];
payRate = new double[totalEmployees];
hoursWorked = new double[totalEmployees];
stage2.close();
}
On the other hand, however, if you do need to use those arrays first, then you could try an ArrayList instead. HTH

Resources