JavaFX Basics write a program that displays a 10-by-10 square matrix. Each element in the matrix is 0 or 1, randomly generated. Display each number centered in a text field. Use TextField setText method to set value 0 or 1 as a string.
As of now I can only print one random number. How can I make display a 10-by-10 matrix?
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import java.util.Random;
public class Matrix extends Application {
public class Matrix extends Application {
Button[][] matrix; //names the grid of buttons
#Override
public void start(Stage primaryStage) {
int SIZE = 10;
int length = SIZE;
int width = SIZE;
GridPane root = new GridPane();
matrix = new Button[width][length];
for(int y = 0; y < length; y++)
{
for(int x = 0; x < width; x++)
{
Random rand = new Random();
int rand1 = rand.nextInt(2);
matrix[x][y] = new Button(/*"(" + rand1 + ")"*/);
matrix[x][y].setText("(" + rand1 + ")"); //
matrix[x][y].setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Random Binary Matrix (JavaFX)");
}
});
root.getChildren().add(matrix[x][y]);
}
}
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Random Binary Matrix (JavaFX)");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You actually did most of the hard work already and the only thing you missed is looking up the GridPaneAPI. What your code does is add 40 buttons on top of each other because you never change the row or column of the GridPane!
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javax.xml.soap.Text;
import java.util.ArrayList;
import java.util.Random;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
int SIZE = 10;
int length = SIZE;
int width = SIZE;
GridPane root = new GridPane();
for(int y = 0; y < length; y++){
for(int x = 0; x < width; x++){
Random rand = new Random();
int rand1 = rand.nextInt(2);
// Create a new TextField in each Iteration
TextField tf = new TextField();
tf.setPrefHeight(50);
tf.setPrefWidth(50);
tf.setAlignment(Pos.CENTER);
tf.setEditable(false);
tf.setText("(" + rand1 + ")");
// Iterate the Index using the loops
root.setRowIndex(tf,y);
root.setColumnIndex(tf,x);
root.getChildren().add(tf);
}
}
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Random Binary Matrix (JavaFX)");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I'm trying to build a space invaders like game.
I've drawn a square and I want to move it down incrementally by using a loop and thread.sleep. However, the square just gets drawn immediately. I understand there are animation paths that could be used but I want to stay low level and just use a coordinate system.
Is there a way of making a timeline animation by using a loop like this?
package com.company;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.shape.Rectangle;
public class Main extends Application {
public static void main(String[] args) {
// write your code here
launch(args);
}
public void start(Stage myStage) throws InterruptedException {
myStage.setTitle("space invaders");
Pane rootNode= new Pane();
Scene myScene=new Scene(rootNode, 400, 800);
myStage.setScene(myScene);
Rectangle r = new Rectangle();
myStage.show();
rootNode.getChildren().add(r);
r.setX(50);
r.setY(50);
r.setWidth(20);
r.setHeight(20);
for (int i = 0; i < 500; i++){
Thread.sleep(2000);
r.setTranslateY(i);
}
}
}
This is a terrible implementation. I would probably use AnimationTimer. This is done with Timeline. It's basically moving right or left. If you hit the right or left bound, drop then move in the opposite direction.
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javafx.animation.KeyFrame;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author blj0011
*/
public class JavaFXApplication343 extends Application
{
int invaderWidth = 30;
int invaderHeight = 10;
int gapBetweenInvaderX = 5;
int gapBetweenInvaderY = 5;
int locationTrackerX;
int locationTrackerY;
int screenWidth = 300;
int screenHeight = 400;
double timeBetweenFrames = .25;
boolean direction = true;
Timeline timeline;
#Override
public void start(Stage primaryStage)
{
Pane pane = new Pane();
locationTrackerX = (screenWidth - (invaderWidth * 6 + gapBetweenInvaderX * 5)) / 2;
locationTrackerY = (screenHeight - (invaderHeight * 6 + gapBetweenInvaderY * 5)) / 7;
List<Rectangle> invaders = new ArrayList();
for (int i = 0; i < 36; i++) {
Rectangle rectangle = new Rectangle(locationTrackerX, locationTrackerY, invaderWidth, invaderHeight);
rectangle.setFill(Color.YELLOW);
invaders.add(rectangle);
System.out.println(locationTrackerX);
locationTrackerX += invaderWidth + gapBetweenInvaderX;
if ((i + 1) % 6 == 0) {
locationTrackerX = (screenWidth / 2) - ((invaderWidth * 6 + gapBetweenInvaderX * 5) / 2);
locationTrackerY += invaderHeight + gapBetweenInvaderY;
}
}
timeline = new Timeline(new KeyFrame(Duration.seconds(timeBetweenFrames), (event) -> {
//Check to see if invader hits bounds
Optional<Rectangle> hitRightOptional = invaders.stream().filter(invader -> invader.getBoundsInLocal().getMaxX() >= pane.getWidth()).findFirst();
Optional<Rectangle> hitLeftOptional = invaders.stream().filter(invader -> invader.getBoundsInLocal().getMinX() <= 0).findFirst();
//Move invaders
if (hitRightOptional.isPresent()) {
invaders.forEach((tempInvader) -> tempInvader.setY(tempInvader.getY() + 10));
timeline.stop();
PauseTransition pause = new PauseTransition(Duration.seconds(timeBetweenFrames));
pause.setOnFinished((pauseEvent) -> {
invaders.forEach(invader -> invader.setX(invader.getX() - 10));
timeline.play();
});
pause.play();
direction = false;
}
else if (hitLeftOptional.isPresent()) {
invaders.forEach((tempInvader) -> tempInvader.setY(tempInvader.getY() + 10));
timeline.stop();
PauseTransition pause = new PauseTransition(Duration.seconds(timeBetweenFrames));
pause.setOnFinished((pauseEvent) -> {
invaders.forEach(invader -> invader.setX(invader.getX() + 10));
timeline.play();
});
pause.play();
direction = true;
}
else {
if (direction) {
invaders.forEach(invader -> invader.setX(invader.getX() + 10));
}
else {
invaders.forEach(invader -> invader.setX(invader.getX() - 10));
}
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
Button btn = new Button();
btn.setText("Start Game");
btn.setOnAction((ActionEvent event) -> {
timeline.play();
btn.setDisable(true);
});
pane.getChildren().addAll(invaders);
pane.setPrefSize(screenWidth, screenHeight);
VBox root = new VBox(pane, new StackPane(btn));
Scene scene = new Scene(root, screenWidth, screenHeight);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Solved :
Task task = new Task<Void>() {
#Override public Void call() throws InterruptedException {
for (int i = 1; i <= 800; i=i+10) {
Thread.sleep(25);
//updateProgress(i, max);
r.setTranslateY(i);
}
return null;
}
};
new Thread(task).start();
I am creating am application that displays circles (of different colors) randomly within each cell of a gridPane.
What i want to do is create a "shuffle" button that changes the position of each circle randomly within the gridPane. However, I keep running into a slurry of problems.
Here is what i have so far. My two classes (have not added XML file):
Controller Class
public class viewController {
//My two Variables, a gridPane and a button
#FXML
private GridPane matrix;
#FXML
private Button shuffleBut;
//my eventHandler event that should (1) add circles to all the cells, and
(2) shuffle them amongst the cells in the gridPane.
void shuffle(ActionEvent e) {
Random r = new Random ();
int rowShuffle = r.next((4-0)+1);
int colShuffle = r.next((4-0)+1);
Circle newCircle = new Circle ();
matrix.add(newCircle, rowShuffle, colShuffle );
}
Main Class
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
// just load fxml file and display it in the stage:
Parent root = FXMLLoader.Load(getClass().getResource("mainUI.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
// main method to support non-JavaFX-aware environments:
public static void main(String[] args) {
// starts the FX toolkit, instantiates this class,
// and calls start(...) on the FX Application thread:
launch(args);
}
Here is an example that demos how to shuffle Circles around in a GridPane. If you add the Circles to an ArrayList, you can remove the Circles from the GridPane. Then you can shuffle the List. Finally, you can add the shuffled list back to the GridPane.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication314 extends Application
{
Random random = new Random();
int numberOfRows = 25;
int numberOfColumns = 25;
#Override
public void start(Stage primaryStage)
{
List<Circle> circles = new ArrayList();
for (int i = 0; i < numberOfColumns * numberOfRows; i++) {
circles.add(new Circle(10, getRandomColor()));
}
GridPane gridPane = new GridPane();
addCirclesToGridPane(gridPane, circles);
gridPane.setPadding(new Insets(20, 20, 20, 20));
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
Collections.shuffle(circles);//Shuffle the List of Circles.
for(int i = 0; i < numberOfColumns * numberOfRows; i++)
{
Circle c = circles.get(i);
GridPane.setColumnIndex(c, i % numberOfColumns);
GridPane.setRowIndex(c, i / numberOfColumns);
}
});
VBox vBox = new VBox(gridPane, new StackPane(btn));
vBox.setMaxSize(Control.USE_COMPUTED_SIZE, Control.USE_COMPUTED_SIZE);
StackPane root = new StackPane(vBox);
root.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
Scene scene = new Scene(root);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
public void addCirclesToGridPane(GridPane gridPane, List<Circle> circles)
{
for (int i = 0; i < numberOfColumns * numberOfRows; i++) {
gridPane.add(circles.get(i), i % numberOfColumns, i / numberOfColumns);
}
}
public Color getRandomColor()
{
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
return Color.rgb(r, g, b);
}
}
I am new to javafx and was using it to carry out a version of the Ant Colony Optimization algorithm. I have written some code that was supposed to display a small circle as the ant which moves about randomly in the plane. This worked fine. But I could not modify the code to display the path of the ant on the scene. Basically I want the path of the ant to be highlighted by lines as the ant moves on a 2D plane.
Here is the code:
import java.util.ArrayList;
import java.util.Random;
//Line can either be a sound or a shape
import javafx.animation.Animation.Status;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.lang.Object;
import javafx.scene.Node;
import javafx.scene.shape.Shape;
import javafx.scene.shape.Line;
public class TestMotion extends Application {
int N = 10;
static ArrayList<Integer> move = new ArrayList<Integer>();
private double sceneWidth = 512;
private double sceneHeight = 512;
MyNode node = new MyNode(0,0,5);
Path pathA = new Path();
int n = 10;
#Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
root.getChildren().addAll(node, pathA);
Scene scene = new Scene( root, sceneWidth, sceneHeight);
primaryStage.setScene( scene);
primaryStage.show();
animate();
}
//convention conversion (i,j) to node number x
public static int convert(int i, int j, int N)
{
return (j*N +i+1);
}
//convention conversion node number x to (i,j)
//implement in order of definition
public static int reconvertY(int x, int N)
{
return (int) java.lang.Math.floor((x-1)/N);
}
public static int reconvertX(int x, int N, int j)
{
return (x-j*N-1);
}
private void animate() {
nextPos(move, N);
int y1 = reconvertY(move.get(move.size()-1), N);
int x1 = reconvertX(move.get(move.size()-1), N, y1);
MyNode here = new MyNode(10*x1, 10*y1, 1);
System.out.println(move.get(move.size()-1));
pathA.getElements().add (new MoveTo ( node.getTranslateX() + node.getBoundsInParent().getWidth() / 2.0, node.getTranslateY() + node.getBoundsInParent().getHeight() / 2.0));
pathA.getElements().add (new LineTo( here.getTranslateX() + here.getBoundsInParent().getWidth() / 2.0, here.getTranslateY() + here.getBoundsInParent().getHeight() / 2.0));
pathA.setStroke(Color.RED);
pathA.setStrokeWidth(1.0);
PathTransition pathTransitionA = new PathTransition();
pathTransitionA.setDuration(Duration.millis(1000));
pathTransitionA.setNode(node);
pathTransitionA.setPath(pathA);
pathTransitionA.play();
pathA = new Path();
pathTransitionA.setOnFinished( new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( pathTransitionA.getStatus() == Status.RUNNING)
{return;}
animate();
}
});
}
//allot new node to the arraylist such that it is adjacent to the previously assigned node
private void nextPos(ArrayList<Integer> array, int N)
{
//I removed this part to save space because it is probably irrelevant the the problem at hand
}
public static void main(String[] args) {
move.add(1);
launch(args);
}
public static class MyNode extends StackPane {
public MyNode(double x, double y, double r) {
// create circle
Circle circle = new Circle();
circle.setRadius(r);
circle.setFill(Color.BLUE);
// set position
setTranslateX( x);
setTranslateY( y);
getChildren().add(circle);
}
}
}
On execution the scene displays the path for the first step only and then stops displaying the path altogether. I cannot figure out why. The path is renewed each time the animate() function runs, and both node and here should be updated regularly. So shouldn't each iteration display the newest path segment of the ant?
Can someone please explain the problem? Is it not possible to exploit Path() and PathTransition() to display these segments and avoid using Line()?
Your approach is not wrong. Only the problem is whenever you are calling the animate(), the path formed is having the coordinates as before. The path coordinates are always returning the following
1.0, 1.0 for moveTo and 5.0,5.0 for LineTo
You need to pass fresh coordinates each time as that the path becomes a new one. Also to keep showing the old path along with the new one, you need to keep adding the newly created path to the Group.
Here's what I have changed in you code. Have a look.
import java.util.ArrayList;
import javafx.animation.Animation.Status;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TestMotion extends Application {
int N = 10;
static ArrayList<Integer> move = new ArrayList<Integer>();
private double sceneWidth = 512;
private double sceneHeight = 512;
MyNode node = new MyNode(0, 0, 5);
Group root; //Made root as global variable
int n = 10;
#Override
public void start(Stage primaryStage) throws Exception {
root = new Group();
root.getChildren().addAll(node);
Scene scene = new Scene(root, sceneWidth, sceneHeight);
primaryStage.setScene(scene);
primaryStage.show();
animate(0.0f, 0.0f, 5.0f, 5.0f); //Passing initial coordinates to the method
}
//convention conversion (i,j) to node number x
public static int convert(int i, int j, int N) {
return (j * N + i + 1);
}
//convention conversion node number x to (i,j)
//implement in order of definition
public static int reconvertY(int x, int N) {
return (int) java.lang.Math.floor((x - 1) / N);
}
public static int reconvertX(int x, int N, int j) {
return (x - j * N - 1);
}
private void animate(float moveX, float moveY, float lineX, float lineY) {
Path pathA = new Path();
root.getChildren().add(pathA);
nextPos(move, N);
int y1 = reconvertY(move.get(move.size() - 1), N);
int x1 = reconvertX(move.get(move.size() - 1), N, y1);
//Applying coordinates as obtained
pathA.getElements().add(new MoveTo(moveX, moveY));
pathA.getElements().add(new LineTo(lineX, lineY));
pathA.setStroke(Color.RED);
pathA.setStrokeWidth(1.0);
PathTransition pathTransitionA = new PathTransition();
pathTransitionA.setDuration(Duration.millis(100));
pathTransitionA.setNode(node);
pathTransitionA.setPath(pathA);
pathTransitionA.play();
pathTransitionA.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (pathTransitionA.getStatus() == Status.RUNNING) {
return;
}
animate(lineX, lineY, lineX + 2, lineY + 2); //previous path's endpoint makes the start point of the new Path
}
});
}
//allot new node to the arraylist such that it is adjacent to the previously assigned node
private void nextPos(ArrayList<Integer> array, int N) {
//I removed this part to save space because it is probably irrelevant the the problem at hand
}
public static void main(String[] args) {
move.add(1);
launch(args);
}
public static class MyNode extends StackPane {
public MyNode(double x, double y, double r) {
// create circle
Circle circle = new Circle();
circle.setRadius(r);
circle.setFill(Color.BLUE);
// set position
setTranslateX(x);
setTranslateY(y);
getChildren().add(circle);
}
}
}
Hope It helps.
I was wondering if it is at all possible to decide the number of rows and columns a gridpane should have.
You can add the required number of ColumnConstraints and RowConstraints to the GridPane. For example:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class GridPaneForceColsAndRows extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 50 ;
final int numRows = 50 ;
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);
}
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
So, I am trying to display a chessboard in javaFX. I will have to perform different operations and draw on some of the tiles so I chose to use a Canvas for each tile and a GridPane to arrange them for me in a grid fashion.
Unfortunately I am having some problems with the resizing of the grid tiles; I want my whole chessboard to automatically adapt its size to the Scene. Therefore, I have added a ChangeListener to both the height and width properties of the GridPane which takes care of resizing the tiles. This only works when the window gets bigger, when the window is reduced to a smaller size everything still gets bigger!
Here's the shortest SSCCE I came up with which reproduces my problem:
package chessboardtest;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.Stage;
public class ChessboardTest extends Application {
final int size = 10;
#Override
public void start(Stage primaryStage) {
VBox root = new VBox();
final GridPane chessboard = new GridPane();
fillChessboard(chessboard, size);
ChangeListener<Number> resizeListener = new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
double newWidth = chessboard.getWidth() / size;
double newHeight = chessboard.getHeight() / size;
for(Node n: chessboard.getChildren()) {
Canvas canvas = (Canvas)n;
canvas.setWidth(newWidth);
canvas.setHeight(newHeight);
}
}
};
chessboard.widthProperty().addListener(resizeListener);
chessboard.heightProperty().addListener(resizeListener);
root.getChildren().add(chessboard);
root.setPadding(new Insets(10));
VBox.setVgrow(chessboard, Priority.ALWAYS);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("chessboard");
primaryStage.setScene(scene);
primaryStage.show();
}
void fillChessboard(GridPane pane, int size) {
class RedrawListener implements ChangeListener<Number> {
Color color;
Canvas canvas;
public RedrawListener(Canvas c, int i) {
if(i % 2 == 0) {
color = Color.BLACK;
}
else {
color = Color.WHITE;
}
canvas = c;
}
#Override
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
canvas.getGraphicsContext2D().setFill(color);
canvas.getGraphicsContext2D().fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
}
for(int row = 0; row < size; row++) {
for(int col = 0, i = row; col < size; col++, i++) {
Canvas c = new Canvas();
RedrawListener rl = new RedrawListener(c, i);
c.widthProperty().addListener(rl);
c.heightProperty().addListener(rl);
pane.add(c, row, col);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
If you don't need a canvas (and you probably don't), just use StackPanes for the squares and make them fill the width and the height. You can always add a canvas (or anything else) to the StackPanes to display their content.
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Chessboard extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
final int size = 8 ;
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col ++) {
StackPane square = new StackPane();
String color ;
if ((row + col) % 2 == 0) {
color = "white";
} else {
color = "black";
}
square.setStyle("-fx-background-color: "+color+";");
root.add(square, col, row);
}
}
for (int i = 0; i < size; i++) {
root.getColumnConstraints().add(new ColumnConstraints(5, Control.USE_COMPUTED_SIZE, Double.POSITIVE_INFINITY, Priority.ALWAYS, HPos.CENTER, true));
root.getRowConstraints().add(new RowConstraints(5, Control.USE_COMPUTED_SIZE, Double.POSITIVE_INFINITY, Priority.ALWAYS, VPos.CENTER, true));
}
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This is a nice solution, but resizing is so much easier with data binding in Java FX. You can hide all listener business this way.
Here is a solution much like James D's, but using Rectangles insread of Canvases for the squares:
public class ResizeChessboard extends Application {
GridPane root = new GridPane();
final int size = 8;
public void start(Stage primaryStage) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
Rectangle square = new Rectangle();
Color color;
if ((row + col) % 2 == 0) color = Color.WHITE;
else color = Color.BLACK;
square.setFill(color);
root.add(square, col, row);
square.widthProperty().bind(root.widthProperty().divide(size));
square.heightProperty().bind(root.heightProperty().divide(size));
}
}
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}