I am trying to write a JavaFX Sudoku program where the user can fill a cell by:
- Clicking one of nine buttons (corresponding to 1-9)
- Clicking one of the cells
The way the code works is that when a button is clicked, the int corresponding to that button is assigned to selectedNum
. And when the Cell is clicked, the Cell assigns its text to selectedNum
. However, this is where the issue occurs--in implementing the setOnAction function inside the Cell
constructor. Cell
cannot access selectedNum
. How can I pass selectedNum when it's a variable that is outside the scope of its class?
Cell Class:
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
/**
* The Cell class inherits StackPane, representing one of the cells in Sudoku.
* @author rkuni
*
*/
public class Cell extends StackPane{
private Text text; //displays the number inside the cell
private Rectangle rect; //visual element for the cell
/**
* Default Constructor for Cell
*/
public Cell() {
text = new Text("");
text.setFont(Font.font(30));
rect = new Rectangle(50, 50);
rect.setStyle("-fx-fill: white; -fx-stroke: black; -fx-stroke-width: 1;");
this.getChildren().add(rect);
this.getChildren().add(text);
this.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
text.setText("" + 1); //when clicked, I want to set text to the number that is selected.
}
});
}
}
Main Class
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Font;
public class Main extends Application {
private int selectedNum = 0;
@Override
public void start(Stage primaryStage) {
try {
Group root = new Group();
Cell cell1 = new Cell();
cell1.setLayoutX(100);
cell1.setLayoutY(100);
root.getChildren().add(cell1);
Button numSelection[] = new Button[9];
for (int i = 0; i < 9; i++) {
final int j = i;
numSelection[i] = new Button("" + (i + 1));
numSelection[i].setLayoutY((i / 3) * 55 + 200);
numSelection[i].setLayoutX((i % 3) * 55 + 630);
numSelection[i].setMinHeight(50);
numSelection[i].setMinWidth(50);
numSelection[i].setFont(Font.font(20));
root.getChildren().add(numSelection[i]);
numSelection[i].setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
selectedNum = j + 1;
}
});
}
Scene scene = new Scene(root,900,500);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Potential Solutions
A potential solution is to not have a Cell class at all, and the code will work. The problem is no longer there because all the variables are within the same scope. However, I'd like to keep the Cell class because it makes for more organized code. Here it is anyway:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
public class Main extends Application {
private int selectedNum; //will take the value of the last pressed button (1-9)
@Override
public void start(Stage primaryStage) {
try {
Group root = new Group();
//setting up a stackpane that will contain a rect and text, making for a "cell"
StackPane stack1 = new StackPane();
Text text1 = new Text("");
Rectangle rect1 = new Rectangle(50,50);
rect1.setStyle("-fx-fill: white; -fx-stroke: black; -fx-stroke-width: 1;");
stack1.getChildren().add(text1);
stack1.getChildren().add(rect1);
stack1.setLayoutX(100);
stack1.setLayoutY(100);
stack1.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
text1.setText("" + selectedNum); //when clicked, set text to the number that is selected.
}
});
//setting up the buttons that will designate which number will go into the cell.
Button numButtons[] = new Button[9];
for (int i = 0; i < 9; i++) {
final int j = i;
numButtons[i] = new Button("" + (i + 1));
numButtons[i].setLayoutY((i / 3) * 55 + 200);
numButtons[i].setLayoutX((i % 3) * 55 + 630);
numButtons[i].setMinHeight(50);
numButtons[i].setMinWidth(50);
numButtons[i].setFont(Font.font(20));
root.getChildren().add(numButtons[i]);
numButtons[i].setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
selectedNum = j + 1;
}
});
}
text1.toFront();
root.getChildren().add(stack1);
Scene scene = new Scene(root,900,500);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I've also thought about overriding the function to add a parameter but haven't gotten that to work successfully.