Need help inserting buttons into Tic Tac Toe game - javafx

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.

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.

JavaFX 11 TableView Cell navigation by TAB key pressed without custom editableCell class

The problem:
I want to navigate through a TableView from one cell to the next right neighbor cell in JavaFX by using the TAB key.
Notice: The TableView is set to editable. And CellSelection is enabled too.
tableReceipt.getSelectionModel().setCellSelectionEnabled(true);
The handling of the KeyPressedEvent seemingly is not my problem, but to request the focus of the single cell on the right of the current cell.
I can focus one cell but when i press the TAB key the focus goes out of the table on other form elements.
The TableView contains some editable TextFieldTableCells and one editable ComboBoxTableCell.
I don't use a custom class for the editable Cells but Code like this:
Callback<TableColumn<Receipt, int>, TableCell<Receipt, int>> tfCallBack = TextFieldTableCell.forTableColumn();
columnAmount.setCellFactory(tfCallBack);
for a TableCell with editable TextField nature.
My question:
How can I implement a solution to solve my problem? A theoretical solution would help too. I allready searched for this topic but only found an example that's using a custom EditableCell class. I think there must be a solution using the callback method like I do.
Solution approach:
tableReceipt.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.TAB) {
tableReceipt.getFocusModel().focusRightCell();
Robot r = new Robot();
r.keyPress(KeyCode.ENTER);
}
}
});
With this code I can get focus of the right cell next to the current one. And I need the ENTER KeyPress to enable the editable mode of the Cell. But when I press TAB on keyboard the new value is not committed. For example I press '2' the default value is '0' and after pressing TAB the value is again '0'.
Question No.2:
How can I combine the code above with a changeListener/onEditCommitListener, that the new value is stored in the cell after pressing TAB?
Thank you.
This may be helpful. You have to manually call it after you complete a cell edit.
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Brian Boutin on 5/14/2019
*/
class CellNav<T> {
private final TableView<T> tableView;
private KeyEvent lastKeyEvent;
private TablePosition editingPosition;
CellNav(TableView<T> tableView) {
this.tableView = tableView;
this.editingPosition = null;
tableView.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.TAB || event.getCode() == KeyCode.ENTER) {
editingPosition = tableView.getEditingCell();
lastKeyEvent = event;
}
});
tableView.setOnMouseReleased(e -> editingPosition = null);
for (TableColumn col : tableView.getColumns()) {
col.setOnEditCancel(event -> editingPosition = null);
}
}
void doCellNav() {
if (editingPosition == null) {
return;
}
if (lastKeyEvent.getCode() == KeyCode.ENTER) {
int selectIdx;
if (lastKeyEvent.isShiftDown()) {
selectIdx = editingPosition.getRow() - 1;
} else {
selectIdx = editingPosition.getRow() + 1;
}
if (selectIdx < 0 ) {
selectIdx = tableView.getItems().size() - 1;
} else if (selectIdx > tableView.getItems().size() - 1) {
selectIdx = 0;
}
tableView.layout();
tableView.scrollTo(selectIdx == 0 ? selectIdx : selectIdx - 1);
tableView.getSelectionModel().clearAndSelect(selectIdx);
tableView.edit(selectIdx, editingPosition.getTableColumn());
} else if (lastKeyEvent.getCode() == KeyCode.TAB) {
TableColumn colToEdit = getNextColumn(!lastKeyEvent.isShiftDown(), editingPosition.getTableColumn());
if (colToEdit != null) {
tableView.layout();
tableView.scrollToColumn(colToEdit);
tableView.edit(editingPosition.getRow(), colToEdit);
}
}
editingPosition = null;
}
boolean isNavigating() {
return editingPosition != null;
}
private TableColumn getNextColumn(boolean forward, TableColumn currentCol) {
List<TableColumn> columns = new ArrayList<>();
for (TableColumn col : tableView.getColumns()) {
if (col.isEditable() && col.isVisible() && (col.getStyleClass().contains("editable-col") || col.getStyleClass().contains("result-col"))) {
columns.add(col);
}
}
if (columns.size() < 2) {
return null;
}
int currentIndex = -1;
for (int i = 0; i < columns.size(); i++) {
if (columns.get(i) == currentCol) {
currentIndex = i;
break;
}
}
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
}
public class ExampleClass{
CellNav cellNav;
public ExampleClass() {
TableView yourTableView = new TableView();
cellNav = new CellNav(yourTableView);
TableColumn someCol = new TableColumn();
someCol.setOnEditCommit(e -> {
//perform a save of your table data here
//pick up cell nav again
if (cellNav.isNavigating()) {
cellNav.doCellNav();
}
});
}
}

gridpane javafx clickable cells that get toggled and untoggled

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

Gluon Mobile Cardpane UI Enhancements: Cardcell Generation/Deletion & Cardpane Styling

I'm trying to create a cardpane with custom HBox CardCells.
Issue #1
How do I set the background of this CardPane? I want it to be transparent, but it won't change from this grey color. I have tried adding styling to the node directly as well as add a custom stylesheet. I have also tried the setBackground method:
Issue #2
Taken from this SO post, I was able to add an animation for cell generation in which it fades in upwards. However, in random card inserts, different cells lose the node that I have embedded in that cell. I don't know if this is because of the recycling concept of these cards (based on Gluon docs) or what:
Issue #3
I created functionality such that the user can delete the cards by swiping left. However, the same issue from Issue #2 arises, but to an even greater extent in which the entire cell is missing but still taking space. If I have only one cell and swipe left, it works all the time. However when I have more than one cell (for example I have 3 cells and I delete the 2nd cell), things get broken, event handlers for cells get removed, swiping left on one cell starts the animation on a cell below it, etc. Is there a way I can perform this functionality or is my best bet to just get rid of the CardPane and use a combination of VBox and HBox elements?
private void addToCardPane(CustomCard newCard) {
ObservableList<Node> items = cardpane.getItems();
boolean override = false;
for (int i = 0; i < cardpane.getItems().size(); i++) {
CustomCard box = (CustomCard) items.get(i);
if (box.checkEquality(newCard)) {
box.increaseNumber(newCard);
override = true;
break;
}
}
if (override == false) {
cardpane.getItems().add(newCard);
cardpane.layout();
VirtualFlow vf = (VirtualFlow) cardpane.lookup(".virtual-flow");
Node cell = vf.getCell(cardpane.getItems().size() - 1);
cell.setTranslateX(0);
cell.setOpacity(1.0);
if (!cardpane.lookup(".scroll-bar").isVisible()) {
FadeInUpTransition f = new FadeInUpTransition(cell);
f.setRate(2);
f.play();
} else {
PauseTransition p = new PauseTransition(Duration.millis(20));
p.setOnFinished(e -> {
vf.getCell(cardpane.getItems().size() - 1).setOpacity(0);
vf.show(cardpane.getItems().size() - 1);
FadeTransition f = new FadeTransition();
f.setDuration(Duration.seconds(1));
f.setFromValue(0);
f.setToValue(1);
f.setNode(vf.getCell(cardpane.getItems().size() - 1));
f.setOnFinished(t -> {
});
f.play();
});
p.play();
}
}
initializeDeletionLogic();
}
private void initializeDeletionLogic() {
VirtualFlow vf = (VirtualFlow) cardpane.lookup(".virtual-flow");
for (int i = 0; i < cardpane.getItems().size(); i++) {
CustomCard card = (CustomCard ) cardpane.getItems().get(i);
Node cell2 = vf.getCell(i);
addRemovalLogicForCell(card, cell2);
}
}
private static double initX = 0;
private void addRemovalLogicForCell(OpioidCard card, Node cell) {
card.setOnMousePressed(e -> {
initX = e.getX();
});
card.setOnMouseDragged(e -> {
double current = e.getX();
if (current < initX) {
if ((current - initX) < 0 && (current - initX) > -50) {
cell.setTranslateX(current - initX);
}
}
});
card.setOnMouseReleased(e -> {
double current = e.getX();
double delta = current - initX;
System.out.println(delta);
if (delta > -50) {
int originalMillis = 500;
double ratio = (50 - delta) / 50;
int newMillis = (int) (500 * ratio);
TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis));
translate.setToX(0);
translate.setNode(cell);
translate.play();
} else {
FadeTransition ft = new FadeTransition(Duration.millis(300), cell);
ft.setFromValue(1.0);
ft.setToValue(0);
TranslateTransition translateTransition
= new TranslateTransition(Duration.millis(300), cell);
translateTransition.setFromX(cell.getTranslateX());
translateTransition.setToX(-400);
ParallelTransition parallel = new ParallelTransition();
parallel.getChildren().addAll(ft, translateTransition);
parallel.setOnFinished(evt -> {
removeCard(card);
ObservableList<CustomCard > cells = FXCollections.observableArrayList();
for(int i = 0; i < this.cardpane.getItems().size(); i++){
cells.add((CustomCard )this.cardpane.getItems().get(i));
}
this.cardpane.getItems().clear();
for(int i = 0; i < cells.size(); i++){
this.cardpane.getItems().add(cells.get(i));
}
initializeDeletionLogic();
initX = 0;
});
parallel.play();
}
});
}
private void removeCard(OpioidCard card) {
for (int i = 0; i < cardpane.getItems().size(); i++) {
if (cardpane.getItems().get(i) == card) {
cardpane.getItems().remove(i);
updateNumber(this.totalNumber);
break;
}
}
for (int i = 0; i < dataList.size(); i++) {
if (dataList.get(i).getName().equalsIgnoreCase(card.getName())) {
dataList.remove(i);
}
}
this.cardpane.layout();
initializeDeletionLogic();
}
WORKING DEMO OF ISSUE:
package com.mobiletestapp;
import com.gluonhq.charm.glisten.animation.FadeInUpTransition;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.CardCell;
import com.gluonhq.charm.glisten.control.CardPane;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.animation.PauseTransition;
import javafx.animation.TranslateTransition;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
public class BasicView extends View {
class CustomCard extends StackPane{
public CustomCard(String text){
this.getChildren().add(new Label(text));
}
}
private static double initX = 0;
private static void addRemovalLogicForCell(CustomCard card, Node cell) {
card.setOnMousePressed(e -> {
initX = e.getX();
});
card.setOnMouseDragged(e -> {
double current = e.getX();
if (current < initX) {
if ((current - initX) < 0 && (current - initX) > -50) {
cell.setTranslateX(current - initX);
}
}
});
card.setOnMouseReleased(e -> {
double current = e.getX();
double delta = current - initX;
System.out.println(delta);
if (delta > -50) {
int originalMillis = 500;
double ratio = (50 - delta) / 50;
int newMillis = (int) (500 * ratio);
TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis));
translate.setToX(0);
translate.setNode(cell);
translate.play();
} else {
FadeTransition ft = new FadeTransition(Duration.millis(300), cell);
ft.setFromValue(1.0);
ft.setToValue(0);
TranslateTransition translateTransition
= new TranslateTransition(Duration.millis(300), cell);
translateTransition.setFromX(cell.getTranslateX());
translateTransition.setToX(-400);
ParallelTransition parallel = new ParallelTransition();
parallel.getChildren().addAll(ft, translateTransition);
parallel.setOnFinished(evt -> {
for(int i = 0; i < cardPane.getItems().size(); i++){
if(cardPane.getItems().get(i) == card){
cardPane.getItems().remove(i);
}
}
initX = 0;
});
parallel.play();
}
});
}
private static CardPane cardPane = null;
public BasicView(String name) {
super(name);
cardPane = new CardPane();
cardPane.setCellFactory(p -> new CardCell<CustomCard>() {
#Override
public void updateItem(CustomCard item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setText(null);
setGraphic(item);
} else {
setText(null);
setGraphic(null);
}
}
});
setCenter(cardPane);
}
private static void addCard(CustomCard newCard){
cardPane.getItems().add(newCard);
cardPane.layout();
VirtualFlow vf = (VirtualFlow) cardPane.lookup(".virtual-flow");
Node cell = vf.getCell(cardPane.getItems().size() - 1);
cell.setTranslateX(0);
cell.setOpacity(1.0);
if (!cardPane.lookup(".scroll-bar").isVisible()) {
FadeInUpTransition f = new FadeInUpTransition(cell);
f.setRate(2);
f.play();
} else {
PauseTransition p = new PauseTransition(Duration.millis(20));
p.setOnFinished(e -> {
vf.getCell(cardPane.getItems().size() - 1).setOpacity(0);
vf.show(cardPane.getItems().size() - 1);
FadeTransition f = new FadeTransition();
f.setDuration(Duration.seconds(1));
f.setFromValue(0);
f.setToValue(1);
f.setNode(vf.getCell(cardPane.getItems().size() - 1));
f.setOnFinished(t -> {
});
f.play();
});
p.play();
}
addRemovalLogicForCell(newCard, cell);
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Basic View");
appBar.getActionItems().add(MaterialDesignIcon.ADD.button(e -> addCard(new CustomCard("Hello"))));
}
}
This leads to the following output when adding and swiping left for deletion:
If you check with ScenicView, you will notice that the CardPane holds a CharmListView control, which in terms uses an inner ListView that takes the size of its parent.
So this should work:
.card-pane > .charm-list-view > .list-view {
-fx-background-color: transparent;
}
As I mentioned, the control is based on a ListView, so the way to provide cells is using the cell factory. As you can read in the control's JavaDoc:
The CardPane is prepared for a big number of items by reusing its cards.
A developer may personalize cell creation by specifying a cell factory through cellFactoryProperty(). The default cell factory is prepared to accept objects from classes that extend Node or other classes that don't extend from Node, in the latter case the card text will be given by the Object.toString() implementation of the object.
If you are not using it yet, consider using something like this:
cardPane.setCellFactory(p -> new CardCell<T>() {
#Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setText(null);
setGraphic(createContent(item));
} else {
setText(null);
setGraphic(null);
}
}
});
This should manage for you the cards layout, avoiding blank cells or wrong reuse of them.
As for the animation, there shouldn't be a problem in using it.
For swipe animations, the Comments2.0 sample provides a similar use case: A ListView where each cell uses a SlidingListTile. Have a look at its implementation.
You should be able to reuse it with the CardPane.
Try it out, and if you still have issues, post a working sample here (or provide a link), so we can reproduce them.
EDIT
Based on the posted code, a comment related to how the factory cell should be set:
All the JavaFX controls using cells (like ListView or TableView), and also the Gluon CardPane, follow the MVC pattern:
Model. The control is bound to a model, using an observable list of items of that model. In the case of the sample, a String, or any regular POJO, or, as the preferred choice, a JavaFX bean (with observable properties).
So in this case, you should have:
CardPane<String> cardPane = new CardPane<>();
View. The control has a method to set how the cell renders the model, the cellFactory. This factory can define just text, or any graphic node, like your CustomCard.
In this case, you should have:
cardPane.setCellFactory(p -> new CardCell<String>() {
private final CustomCard card;
{
card = new CustomCard();
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
card.setText(item);
setGraphic(card);
setText(null);
} else {
setGraphic(null);
setText(null);
}
}
});
where:
class CustomCard extends StackPane {
private final Label label;
public CustomCard(){
label = new Label();
getChildren().add(label);
}
public void setText(String text) {
label.setText(text);
}
}
Internally, the control uses a VirtualFlow that manages to reuse cells, and only modify the content (the model) when scrolling.
As you can see in the cell factory, now you'll iterate over the model (String), while the CustomCard remains the same, and only the content its updated.
Using this approach doesn't present any of the issues you have described, at least when adding cells.
EDIT 2
I've come up with a solution that works fine for me and should solve all the issues mentioned. Besides what was mentioned before, it is also required restoring the transformations applied to the CustomCard in the updateItem callbacks.
public class BasicView extends View {
private final CardPane<String> cardPane;
public BasicView(String name) {
super(name);
cardPane = new CardPane<>();
cardPane.setCellFactory(p -> new CardCell<String>() {
private final CustomCard card;
private final HBox box;
{
card = new CustomCard();
card.setMaxWidth(Double.MAX_VALUE);
card.prefWidthProperty().bind(widthProperty());
box = new HBox(card);
box.setAlignment(Pos.CENTER);
box.setStyle("-fx-background-color: grey");
addRemovalLogicForCell(card);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
card.setText(item);
card.setTranslateX(0);
card.setOpacity(1.0);
setGraphic(box);
setText(null);
} else {
setGraphic(null);
setText(null);
}
}
});
setCenter(cardPane);
}
class CustomCard extends StackPane {
private final Label label;
public CustomCard(){
label = new Label();
label.setStyle("-fx-font-size: 20;");
getChildren().add(label);
setStyle("-fx-padding: 20; -fx-background-color: white");
setPrefHeight(100);
}
public void setText(String text) {
label.setText(text);
}
public String getText() {
return label.getText();
}
}
private double initX = 0;
private void addRemovalLogicForCell(CustomCard card) {
card.setOnMousePressed(e -> {
initX = e.getX();
});
card.setOnMouseDragged(e -> {
double current = e.getX();
if ((current - initX) < 0 && (current - initX) > -50) {
card.setTranslateX(current - initX);
}
});
card.setOnMouseReleased(e -> {
double current = e.getX();
double delta = current - initX;
if (delta < 50) {
if (delta > -50) {
int originalMillis = 500;
double ratio = (50 - delta) / 50;
int newMillis = (int) (500 * ratio);
TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis));
translate.setToX(0);
translate.setNode(card);
translate.play();
} else {
FadeTransition ft = new FadeTransition(Duration.millis(300), card);
ft.setFromValue(1.0);
ft.setToValue(0);
TranslateTransition translateTransition
= new TranslateTransition(Duration.millis(300), card);
translateTransition.setFromX(card.getTranslateX());
translateTransition.setToX(-400);
ParallelTransition parallel = new ParallelTransition();
parallel.getChildren().addAll(ft, translateTransition);
parallel.setOnFinished(evt -> {
cardPane.getItems().remove(card.getText());
initX = 0;
});
parallel.play();
}
}
});
}
private void addCard(String newCard){
cardPane.getItems().add(newCard);
cardPane.layout();
VirtualFlow vf = (VirtualFlow) cardPane.lookup(".virtual-flow");
IndexedCell cell = vf.getCell(cardPane.getItems().size() - 1);
cell.setTranslateX(0);
cell.setOpacity(0);
if (! cardPane.lookup(".scroll-bar").isVisible()) {
FadeInUpTransition f = new FadeInUpTransition(cell, true);
f.setRate(2);
f.play();
} else {
PauseTransition p = new PauseTransition(Duration.millis(20));
p.setOnFinished(e -> {
vf.show(cardPane.getItems().size() - 1);
FadeInTransition f = new FadeInTransition(cell);
f.setRate(2);
f.play();
});
p.play();
}
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Basic View");
appBar.getActionItems().add(MaterialDesignIcon.ADD.button(e -> addCard("Hello #" + new Random().nextInt(100))));
}
}

How do I sort through an array of buttons to see if only one is left enabled?

How do I sort through an array of buttons to see if only one is left enabled? I am creating a Sudoku solver and need to check if there is only one button left unselected in each row, column, or box and if it is to highlight the last remaining option. I can't find a command that will allow me to check each individual cell in the row to see if ONLY one is left. This is what I have so far
public class SudoHelper extends Application
{
public boolean [][][] DisabledCell = new boolean[3][9][9]; // Creates our array
Scene scene;
Pane pane;
Pane main;
BookMark bane;
#Override
public void start (Stage primaryStage)
{
for(int a = 0;a<3;a++)
{
for(int b=0;b<9;b++)
{
for(int c=0; c<9;c++)
{
DisabledCell[a][b][c]=false;
}
}
}
mouseClicks = new MouseEvent[0];
SmartCell[] currentGame = new SmartCell[81];
pane = new Pane();
pane.setPrefSize(684, 702);
int x,y;
x=y=0;
main = new Pane();
for(int i=0; i<81; i++)
{
currentGame[i]= new SmartCell(i);
currentGame[i].setLayoutX(x);
currentGame[i].setLayoutY(y);
pane.getChildren().add(currentGame[i]);
x+=76; // Sets the layout for out array of SmartCells
if(x==684) // and puts our additional buttons on the screen
{ // With our scene and stage
x=0;
y+=78;
}
}
main.setPrefSize(1100, 702);
main.getChildren().add(pane);
bane= new BookMark();
scene = new Scene(main);
main.getChildren().add(bane);
bane.setPrefSize(416, 702);
bane.setLayoutX(685);
bane.setLayoutY(0);
primaryStage.setScene(scene);
primaryStage.setTitle("Sudoku Helper");
primaryStage.show();
}
public static void main(String[] args)
{
Application.launch(args); // Starts the game
}
class BookMark extends Pane
{
class List
{
String[] MyList=new String[0];
public void Add(String Add)
{
if(this.MyList.length>0)
{
String[] Resize = new String[this.MyList.length+1];
for(int i=0;i<this.MyList.length;i++)
{
Resize[i]=this.MyList[i];
}
Resize[this.MyList.length+1]=Add;
}
else
{
this.MyList = new String[1];
this.MyList[0]=Add;
}
}
public void Clear()
{
this.MyList = new String[0];
}
}
Button lkm = new Button("Load Bookmark"); // Creates our load bookmark button
Button bkm = new Button("Save Bookmark"); // Creates out save bookmark button'
final ToggleGroup group1 = new ToggleGroup();
final ToggleGroup group2 = new ToggleGroup();
RadioButton rl1a = new RadioButton("Rule One All"); // Creates rule one radiobutton
RadioButton rl1s = new RadioButton("Rule One Click"); // Creates Rule one click radiobutton
RadioButton rl2s = new RadioButton("Rule Two Click"); // Creates rule two click radiobutton
RadioButton rl2a = new RadioButton("Rule Two All"); // Create rule two radiobutton
void ruleTwo()
{
}
void ruleOne()
{
int _x,_y;
int B=10;
String[]Getloc = name.split("~");
int loc = Integer.parseInt(Getloc[1]);
_y = loc%9;
if(loc<8) // checking which row we are looking at
{
_x=0;
for(_x=0; loc<8;)
{
if()
{
}
}
}
else if(loc<18)
{
_x=1;
}
else if(loc<27)
{
_x=2;
}
else if(loc<36)
{
_x=3;
}
else if(loc<45)
{
_x=4;
}
else if(loc<54)
{
_x=5;
}
else if(loc<63)
{
_x=6;
}
else if(loc<72)
{
_x=7;
}
else
{
_x=8; // checks blocks were looking at
}
if(_y>=0&&_y<=2) // checks which block we are in
{
if(_x>=0&&_x<=2)
{
B=0;
}
else if(_x>=3&&_x<=5)
{
B=1;
}
else if(_x>=6&&_x<=8)
{
B=2;
}
}
else if(_y>=3&&_y<=5)
{
if(_x>=0&&_x<=2)
{
B=3;
}
else if(_x>=3&&_x<=5)
{
B=4;
}
else if(_x>=6&&_x<=8)
{
B=5;
}
}
else if(_y>=6&&_y<=8)
{
if(_x>=0&&_x<=2)
{
B=6;
}
else if(_x>=3&&_x<=5)
{
B=7;
}
else if(_x>=6&&_x<=8)
{
B=8;
}
}
}
BookMark() // Our buttons specifications (Location font ect)
{
this.bkm = new Button("Save Bookmark");
this.lkm = new Button("Load Bookmark");
this.bkm.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.bkm.setLayoutX(10);
this.bkm.setLayoutY(10);
this.lkm.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.lkm.setLayoutX(150);
this.lkm.setLayoutY(10);
this.rl1a.setLayoutX(10);
this.rl1a.setLayoutY(250);
this.rl2a.setLayoutX(10);
this.rl2a.setLayoutY(500);
this.rl2s.setLayoutX(250);
this.rl1s.setLayoutY(250);
this.rl1s.setLayoutX(250);
this.rl2s.setLayoutY(500);
this.rl1a.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl1s.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl2a.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl2s.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.group1.getToggles().add(this.rl1a);
this.group1.getToggles().add(this.rl1s);
this.group2.getToggles().add(this.rl2a);
this.group2.getToggles().add(this.rl2s);
BookMark.this.getChildren().add(this.lkm);
BookMark.this.getChildren().add(this.bkm);
BookMark.this.getChildren().add(this.rl1a);
BookMark.this.getChildren().add(this.rl1s);
BookMark.this.getChildren().add(this.rl2a);
BookMark.this.getChildren().add(this.rl2s);
// bkm.setOnMouseClicked(e -> Save(e));
}
}
private MouseEvent[] mouseClicks;
class SmartCell extends StackPane
{
GridPane buttonPane;
Pane valPane;
Text textVal;
Button [] btn;
String name;
SmartCell(int nameint)
{
buttonPane = new GridPane();
btn = new Button[10];
for(int i = 1; i <= 9; i++)
{
btn[i] = new Button(i+""); // Turns i into a String
btn[i].setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
btn[i].setOnMouseClicked(e -> mouseHandler(e));
buttonPane.add(btn[i], (i-1)%3, (i-1)/3);
}
// When the user clicks one of the 9 buttons, we want to take the number of the button
// they clicked, and set the text on the text pane to that number, hide the 9 buttons,
// and show the text pane.
name = "SmartCell~"+String.valueOf(nameint);
textVal = new Text(25, 55, "");
textVal.setFont(Font.font("Arial", 48));
textVal.setTextAlignment(TextAlignment.CENTER);
valPane = new Pane();
valPane.setStyle("-fx-border-color:black; -fx-border-stroke-width:1");
valPane.getChildren().add(textVal);
getChildren().add(buttonPane); // Add the pane with the 9 buttons to the cell
getChildren().add(valPane); // Add the pane with the one piece of text to the cell
buttonPane.setVisible(true); // We start out showing the 9 buttons
valPane.setVisible(false); // ...NOT showing the pane with the single text
} // end constructor
void disqual(MouseEvent e)
{
MouseEvent[] ResizeMouse = new MouseEvent[SudoHelper.this.mouseClicks.length+1];
ResizeMouse[ResizeMouse.length-1]=e;
SudoHelper.this.mouseClicks = ResizeMouse;
int _x,_y;
int B=10;
String[]Getloc = name.split("~");
int loc = Integer.parseInt(Getloc[1]);
_y = loc%9;
if(loc<8) // checking which row we are looking at
{
_x=0;
}
else if(loc<18)
{
_x=1;
}
else if(loc<27)
{
_x=2;
}
else if(loc<36)
{
_x=3;
}
else if(loc<45)
{
_x=4;
}
else if(loc<54)
{
_x=5;
}
else if(loc<63)
{
_x=6;
}
else if(loc<72)
{
_x=7;
}
else
{
_x=8; // checks blocks were looking at
}
if(_y>=0&&_y<=2) // checks which block we are in
{
if(_x>=0&&_x<=2)
{
B=0;
}
else if(_x>=3&&_x<=5)
{
B=1;
}
else if(_x>=6&&_x<=8)
{
B=2;
}
}
else if(_y>=3&&_y<=5)
{
if(_x>=0&&_x<=2)
{
B=3;
}
else if(_x>=3&&_x<=5)
{
B=4;
}
else if(_x>=6&&_x<=8)
{
B=5;
}
}
else if(_y>=6&&_y<=8)
{
if(_x>=0&&_x<=2)
{
B=6;
}
else if(_x>=3&&_x<=5)
{
B=7;
}
else if(_x>=6&&_x<=8)
{
B=8;
}
};
int CellNum =Integer.parseInt(((Button)e.getSource()).getText());
if(DisabledCell[0][_x][CellNum-1]==true||DisabledCell[1][_y][CellNum-1]==true||DisabledCell[2][B][CellNum-1]==true)
{
disqualify(Integer.parseInt(((Button)e.getSource()).getText()));
return;
}
DisabledCell[0][_x][CellNum-1]=true;
DisabledCell[1][_y][CellNum-1]=true;
DisabledCell[2][B][CellNum-1]=true;
textVal.setText(((Button)e.getSource()).getText());
buttonPane.setVisible(false);
valPane.setVisible(true);
for(int i = 1; i <= 9; i++)disqualify(i); // Since we have locked in, all others are out of play
// in this cell
int c = 0;
int z = 0;
switch(B)
{ // Figures out which block our selected number is in.
case 0: z=0;
break; // ^
case 1: z=27;
break; // ^
case 2: z=54;
break; // ^
case 3: z=3;
break; // ^
case 4: z=30;
break; // ^
case 5: z=57;
break; // ^
case 6: z=6;
break; // ^
case 7: z=33;
break; // ^
case 8: z=60;
break; // ^
}
for(int w = 0; w<9; w++)
{
Object xob =SudoHelper.this.pane.getChildren().get((_x*9)+w);
SmartCell d =SmartCell.class.cast(xob); // Disqualifies x cells
d.disqualify(CellNum);
xob=d;
Object yob =SudoHelper.this.pane.getChildren().get(_y+(9*w));
SmartCell b =SmartCell.class.cast(yob); // Disqualifies Y Cells
b.disqualify(CellNum);
yob=b;
Object zob =SudoHelper.this.pane.getChildren().get(z+c);
SmartCell a =SmartCell.class.cast(zob);
a.disqualify(CellNum); // Disqualifies boxes
zob=a;
c++;
if(c==3)
{
z+=9;
c=0;
}
}
}
void mouseHandler(MouseEvent e)
{
// When any button gets clicked, we take the text from the button, put it on the Text
// shape, hide the pane with the 9 buttons, and show the text pane, making it look like
// the 9 buttons have "gone", and the new value that we have "locked in" has taken their place.
//
if(e.getSource() instanceof Button)
{
// If this was a right click, then just disable this button; If it was a left click then lock
// in the value this button represents.
if(e.getButton() == MouseButton.SECONDARY)
{
disqualify(Integer.parseInt(((Button)e.getSource()).getText()));
// disables button after clicked
return;
}
// System.out.print("A button was clicked"); // for debugging
disqual(e);
} // end if source was a button
} // end mouseHandler
void disqualify(int buttonNo)
{
// When we are called, we disable button #buttonNo in this cell
btn[buttonNo].setDisable(true);
btn[buttonNo].setStyle("-fx-base:black; -fx-text-fill:black; -fx-opacity:1.0"); // Sets color of cells and numbers after disabled.
}
public String toString()
{
// The toString representation of a cell is a string containing a list of
// the values "still in play" --- the remaining candidate values --- for the cell
//
// Start with an empty string. Visit all 9 buttons, and if a given button is
// not disabled (i.e still in play), then add its number (from the text on the
// button) to our string
//
String result = "";
for(int i = 1; i <= 9; i++)
if(!btn[i].isDisabled())
result += i;
return result;
}
}
private boolean[] InitalizeTile() // Initalizes our board of 81 cells
{
boolean[] newbool = new boolean[81];
for(int i=0; i<81; i++)
{
newbool[i] = false;
}
Random R = new Random();
for(int j=0; j<0; j++)
{
while(true)
{
int W = R.nextInt(81);
if(newbool[W]==false)
{
newbool[W]=true;
break;
}
}
}
return newbool;
}
}
All I really need to know is how to look at an array of buttons and see if only one is left enabled.
Arrays.stream(buttons).filter(button -> !button.isDisabled()).count() == 1
Sample application:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.util.Arrays;
public class DisabledButtonCount extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button[] buttons = {
new Button("1"),
new Button("2"),
new Button("3")
};
buttons[1].setDisable(true);
buttons[2].setDisable(true);
System.out.println(
"Only one button enabled? " +
(Arrays.stream(buttons).filter(button -> !button.isDisabled()).count() == 1)
);
Platform.exit();
}
}

Resources