How do I draw 49 rectangles with nested loops with javafx? - java

I have to use a double array to make 49 squares. What I have only given me one rectangle.
Rectangle[][] rectArray = new Rectangle[7][7];
//grid is a GridPane containing 49 rectangles.
GridPane grid = new GridPane();
//---- add 49 rectangles to the grid pane, it is recommended to use nested loops
for(int i = 0; i < rectArray.length; i++)
{
for(int j = 0; j < rectArray.length; j++)
{
rectArray[i][j] = new Rectangle(470/7,390/7);
rectArray[i][j].setStroke(Color.BLACK);
rectArray[i][j].setFill(Color.WHITE);
grid.getChildren().add(rectArray[i][j]);
}
}

Add
GridPane.setConstraints(rectArray[i][j], i, j);
right before you add the rectangle to the grid. Right now all the rectangles are put at the same position (0, 0), so they overlap and look like one.

Related

JavaFX creating a game board with GridPane

When the application is run the game board shows fine, although when a tile is clicked the text always shows in the top left corner of the board [0][0].
Also I am struggling with the logic. I have a int board matrix with a function makeMove which to add a players move to the matrix, although I can't get the player to make a move on the matrix and also print a corresponding "O" on the tile index.
How would I create a function that can be passed a row, col index and alter the board matrix and print the player piece on the GUI (e.g.for AI move)
And also when the GUI tile is clicked by the player to then make the corresponding move.
So far I have created a GridPane and added Rectangle with text at each index for the GUI.
I have created a Board class which constructs an int board matrix to hold player moves (P1, P2, empty).
public class Board {
private int[][] board_matrix;
private int board_size;
private int win_length;
public Board(int board_size, int win_length) {
this.board_matrix = new int[board_size][board_size];
this.board_size = board_size;
this.win_length = win_length;
for (int i = 0; i < board_size; i++) {
for (int j = 0; j < board_size; j++) {
this.board_matrix[i][j] = 0;
}
}
}
public void make_move(int player, int x_pos, int y_pos) {
if (player == 1) board_matrix[x_pos][y_pos] = 1;
else board_matrix[x_pos][y_pos] = 2;
}
public class BoardGUI_ extends Application {
private final int BOARD_SIZE = 15;
public Parent createBoard() {
GridPane gameBoard = new GridPane();
gameBoard.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Rectangle tile = new Rectangle(50, 50);
tile.setFill(Color.BURLYWOOD);
tile.setStroke(Color.BLACK);
Text text = new Text();
text.setFont(Font.font(40));
GridPane.setRowIndex(tile, i);
GridPane.setColumnIndex(tile, j);
tile.setOnMouseClicked(event -> drawMove(text));
gameBoard.getChildren().addAll(tile, text);
}
}
return gameBoard;
}
public void drawMove(Text text) {
text.setText("O");
text.setFill(Color.BLACK);
}
If you want to add a Text object on top of a Rectangle object wrap both in a StackPane:
public Parent createBoard() {
GridPane gameBoard = new GridPane();
gameBoard.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Rectangle tile = new Rectangle(50, 50);
tile.setFill(Color.BURLYWOOD);
tile.setStroke(Color.BLACK);
Text text = new Text();
text.setFont(Font.font(40));
gameBoard.add(new StackPane(tile, text), j, i);
//GridPane.setRowIndex(tile, i);
//GridPane.setColumnIndex(tile, j);
//gameBoard.getChildren().addAll(tile, text);
tile.setOnMouseClicked(event -> drawMove(text));
}
}
return gameBoard;
}
In your loop you are setting the row and column of the 'tile' node, but not the 'text' node. So you have all of your text nodes at 0,0.
It seems you want the tiles to be StackPanes as c0der suggests. With the Text node on top of the tile.
I think makes sense to create a Tile object, possibly derived from StackPane, and use it to manage the each tile. It would be responsible for the background color and text shown. It's not clear at this point if the Rectangle is even needed. You could just set the background and border of the StackPane.

Adjusting textfield size in grid

Got a GridPane with TextFields in which I want to change the size of them, so they can match they squares the grid creates.
GridPane grid = new GridPane();
grid.setPadding(new Insets(50,50,50,50));
TextField[][] textFields = new TextField[9][9];
//En loop för att generera fältet börjar här
for(int x =0; x < 9; x++){
for(int y= 0; y < 9; y++){
grid.setStyle("-fx-background-color: black, -fx-control-inner-background; -fx-background-insets: 0, 2; -fx-padding: 2;");
TextField textField = new TextField("");
textField.setStyle("-fx-pref-width: 10em;");
textField.setStyle("-fx-pref-height: 10em;");
textField.setFont(Font.font("Serif", FontWeight.LIGHT, 20));
GridPane.setConstraints(textField, y, x);
grid.getChildren().add(textField);
textFields[x][y]=textField;
textFields[x][y].setText("" + KeepingUpWithTheSudokus.getNum(x, y));
// textFields[x][y].setPrefHeight(100);
// textFields[x][y].setPrefWidth(20);
}
}
Tried by using setPrefWidth & Height but left the grid only stretched at the height. Searching for a simple way to change the size.

Print a 2d array of objects

I have a class called squares and then I have a class called shapes. In this class is a 12x5 2d array of shapes. In the squares class is a method called draw that draws the square at (550, 75) . The squares have width of 25 and a height of 25. The draw method in the shapes class looks like
public void draw(Graphics g) {
for (i = 0; i < shapes.length; i++) {
for (j = 0; j < shapes[i].length; j++) {
shapes[i][j] = new Square();
shapes[i][j].draw(g);
}
}
}
This draws all the squares on top of each other. How can I draw them in a 12 by 5 format? The size of the window is 600 by 600 if that helps.
Change the draw method in the Squares class to take x and y coordinates as parameters.
You can then change your loop to:
for (i = 0; i < shapes.length; i++) {
for (j = 0; j < shapes[i].length; j++) {
shapes[i][j] = new Square();
shapes[i][j].draw(g, i * 25, j * 25);
}
}
This will mean each square is draw in to the correct position.
-- Edit --
If you can't change the draw parameters, you can add a new constructor for the Square class. This does not require its superclass to have that constructor.
int x;
int y;
public Square(int x, int y) {
this.x = x;
this.y = y;
}
Then pass in the coordinates for that Square when you create it, and modify the draw method appropriately to use these.
Alternatively, if you can't change the Squares class at all, you could translate the graphics coordinates. The square gets drawn at (550, 75), so if we translate the graphics coordinates by (-550, -75) it will appear as if we are drawing at (0,0). We can then incrementally translate for each subsequent square.
g.translate(-550, -75);
for (i = 0; i < shapes.length; i++) {
for (j = 0; j < shapes[i].length; j++) {
shapes[i][j] = new Square();
shapes[i][j].draw(g);
g.translate(0, 25); //Move down by 25
}
g.translate(25, 0); //Move across by 25
}
(Note that I haven't tested this.)

JavaFX clock number transitions

I am attempting to create a clock in JavaFX, everything worked out well, except for the numbers which represent the time (from 1 to 12).
I have this piece of code:
Group numbers = new Group();
for(int i = 0; i < 12; i++){
//create a label.
Label label = new Label(String.valueOf(i));
//center it
label.setTranslateX(100);
label.setTranslateY(100);
label.getTransforms().add(new Rotate(i * (360 / 12)));
//rotate it.
numbers.getChildren().add(label);
}
This doesn't work, the numbers are just rotated in the center, but i want them to move outside (to the edge of the outer circle, like a normal clock.
Can someone help me?
Thank you very much.
If you combine Translate with Rotate transforms:
Group numbers = new Group();
for(int i = 0; i < 12; i++){
//create a label.
Label label = new Label(String.valueOf(i==0?12:i));
label.getTransforms().add(new Rotate(i * (360d / 12d)));
label.getTransforms().add(new Translate(100d,100d));
numbers.getChildren().add(label);
}
You will have a 'rotated' clock:
But as you can see, you are rotating your labels, not their position.
One way to approach this is finding the position of each label by using a small Circle, rotating it to its final position and then moving the label:
Group numbers = new Group();
for(int i = 0; i < 12; i++){
//create a label.
Label label = new Label(String.valueOf(i==0?12:i));
Circle c=new Circle(1);
c.getTransforms().add(new Rotate(i * (360d / 12d)));
c.getTransforms().add(new Translate(0,-100));
label.setTranslateX(c.localToParent(0,0).getX());
label.setTranslateY(c.localToParent(0,0).getY());
numbers.getChildren().addAll(c,label);
}
Note I've adjusted the translation to start right at the 12 hour position.
You will notice the labels are located down and right from their circle, so you should move them accordingly.
EDIT
To avoid the need of fixing the labels position, you can use a StackPane to wrap each pair of circles and labels:
for(int i = 0; i < 12; i++){
Label label = new Label(String.valueOf(i==0?12:i));
Circle c=new Circle(1);
c.getTransforms().add(new Rotate((i) * (360d / 12d)));
c.getTransforms().add(new Translate(0,-100d));
label.setTranslateX(c.localToParent(0,0).getX());
label.setTranslateY(c.localToParent(0,0).getY());
StackPane sp = new StackPane(c,label);
numbers.getChildren().add(sp);
}
Finally, have a look at this question, maybe it's easier just using a circular pane.

Why do I only need to loop 23 times to draw 24 rectangles?

I've just encountered a strange behavior of the for loop and can't find an explanation.
I have a 2D game with this logical element which is a field.
//Declaration of the JPanel logical size.
private int[][] grid = new int[24][12];
Number of rows is 24, right?
I am painting this grid using this:
for (int r = 0; r < grid.length; r++ )
for (int c = 0; c < grid[r].length; c++)
Then I decided not to paint the last row and did this:
r < grid.length - 1;
nothing happened. I thought maybe I need parentheses. I added them and it still didn't work.
Then I changed it to
r < grid.length - 2;
And under this condition the last row was not painted as I originally wanted.
But now I am confused because mathematically: grid.length - 2 = 22; r < 22 means r(max) == 21 which means I am supposed to have two rows not painted. What am I missing?
Test case:
class Action extends JPanel {
public static final int FRAME_SIZE_X = 370;
public static final int FRAME_SIZE_Y = 720;
private int[][] grid = new int[24][12];
public Action() { //Setting everything for JPanel
Dimension actionDimension = new Dimension(360, 690);
setPreferredSize(actionDimension);
setVisible(true);
//...
}
#Override
protected void paintComponent(Graphics pen) {
super.paintComponent(pen);
for (int r = 0; r < grid.length - 2; r++) //Line with a problem
for (int c = 0; c < grid[r].length; c++) {
// [set up pen, etc.]
// draw line
pen.drawRect(c * 30, r * 30, FRAME_SIZE_X / 12, FRAME_SIZE_Y / 24);
}
}
}
It's late, and I know nothing about JPanel in any case, but...
public static final int FRAME_SIZE_X = 370;
public static final int FRAME_SIZE_Y = 720;
...
Dimension actionDimension = new Dimension(360, 690);
Pretty sure your panel is exactly one row (30 units) shorter than your frame - so even if you're looping 24 times and rendering 24 rows, the last one's getting clipped since there's only room for 23 rows on the screen.
Expand the panel to a height of 720 (or more), and I'll bet you notice the difference between 23 and 24 rows...
Take out a piece of paper, and draw a nice large rectangle on it. This is your JPanel. For the sake of this example, we're going to turn grid length into 3.
Take out a different color pen, and draw your first rectangle. This should go from the top left corner to the top right corner, down a third of the JPanel, back across, and back to the top left corner.
Now draw your second rectangle. We'll start a third of the JPanel down, go across to the right, go down another third, back across, and back up to where we started.
Now for the third one. But you'll notice you don't actually need to draw it. Why? The two sides and the bottom are already drawn by the JPanel, and the top is the same line as the bottom of the immediately prior row.
So while yes, another rectangle is drawn by Swing, you just don't see it because every line that it draws has already been drawn by something else. Likewise, to remove the last row, you need to stop drawing the last two rows. (You'll notice on your piece of paper that you get two rows only if you draw one rectangle.)
Note that if you change pen color between drawing your JPanel and your rows, it's a lot easier to see the problem.
for (int r = 0; r < grid.length; r++ )
If grid.length is 24, that iterates 24 times. You're forgetting about the zero. Or else your observations are awry.

Categories