I have this piece of code here that has a borderpane as a parent and 2 other panes, one is a minesweeper game and the other is an empty pane with a black background, the minesweeper game is set to be in the center of the borderpane and the empty pane is set to be in the bottom. Right now when I run the code, it will only show the minesweeper game and not the empty pane (can be seen in the image). How do I make it show the empty pane at the bottom of the borderpane?
(Layout as of right now)
package project;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
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;
import javafx.stage.Stage;
public class MinesweeperApp extends Application {
private static final int TILE_SIZE = 40;
private static final int W = 800;
private static final int H = 800;
private static final int X_TILES = W / TILE_SIZE;
private static final int Y_TILES = H / TILE_SIZE;
private Tile[][] grid = new Tile[X_TILES][Y_TILES];
// private ArrayList[][] grid = new ArrayList[X_TILES][Y_TILES];
private Scene scene;
private Parent createContent() {
BorderPane root = new BorderPane();
Pane middlepane = new Pane();
Pane lowerPane = new Pane();
lowerPane.setStyle("-fx-background-color: black;");
root.setTop(lowerPane);
root.setBottom(middlepane);
middlepane.setPrefSize(W, H);
for (int y = 0; y < Y_TILES; y ) {
for (int x = 0; x < X_TILES; x ) {
Tile tile = new Tile(x, y, Math.random() < 0.2);
grid[x][y] = tile;
middlepane.getChildren().add(tile);
}
}
for (int y = 0; y < Y_TILES; y ) {
for (int x = 0; x < X_TILES; x ) {
Tile tile = grid[x][y];
if (tile.hasBomb)
continue;
long bombs = getNeighbors(tile).stream().filter(t -> t.hasBomb).count();
if (bombs > 0)
tile.text.setText(String.valueOf(bombs));
}
}
return root;
}
private List<Tile> getNeighbors(Tile tile) {
List<Tile> neighbors = new ArrayList<>();
// ttt
// tXt
// ttt
int[] points = new int[] {
-1, -1,
-1, 0,
-1, 1,
0, -1,
0, 1,
1, -1,
1, 0,
1, 1
};
for (int i = 0; i < points.length; i ) {
int dx = points[i];
int dy = points[ i];
int newX = tile.x dx;
int newY = tile.y dy;
if (newX >= 0 && newX < X_TILES
&& newY >= 0 && newY < Y_TILES) {
neighbors.add(grid[newX][newY]);
}
}
return neighbors;
}
private class Tile extends StackPane {
private int x, y;
private boolean hasBomb;
private boolean isOpen = false;
private Rectangle border = new Rectangle(TILE_SIZE - 2, TILE_SIZE - 2);
private Text text = new Text();
public Tile(int x, int y, boolean hasBomb) {
this.x = x;
this.y = y;
this.hasBomb = hasBomb;
border.setStroke(null);
border.setFill(Color.NAVY);
text.setFont(Font.font(18));
text.setText(hasBomb ? "X" : "");
text.setVisible(false);
getChildren().addAll(border, text);
setTranslateX(x * TILE_SIZE);
setTranslateY(y * TILE_SIZE);
setOnMouseClicked(e -> open());
}
public void open() {
System.out.println("clicked");
System.out.println("x: " this.x " " "y: " this.y);
if (isOpen){
return;
}
if (hasBomb) {
System.out.println("Game Over");
scene.setRoot(createContent());
return;
}
isOpen = true;
text.setVisible(true);
border.setFill(Color.RED);
if (text.getText().isEmpty()) {
getNeighbors(this).forEach(Tile::open);
}
}
}
@Override
public void start(Stage stage) throws Exception {
scene = new Scene(createContent());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
CodePudding user response:
As an aside, your original root.setBottom(middlepane)
may be misleading.
CodePudding user response:
If you want to “see” a Pane which has no content, i.e. take up space in the layout, you can set size constraints on it.
You could configure the min width or height, or, pref width or height, or any combination of those that will make the app behave as you desire.
For example to set a min height for the top pane in a border pane
BorderPane borderPane = new BorderPane();
Pane top = new Pane();
top.setMinHeight(15);
borderPane.setTop(top);
Or you could put some content in the pane and make it invisible until it is needed.
For example:
Label header = new Label("header");
header.setVisible(false);
Pane top = new Pane(header);
borderPane.setTop(top);
This works because things in the scene graph which are not visible still take up layout space, even though they are not displayed, unless you also call setManaged(false).
For the specific case of a label, you wouldn’t need the visibility setting, you could just set the label to an empty string and it would still take up room, even though nothing would be shown.
For myself, I try to avoid sizing hints where I can so I would use an empty label. Or, set the visibility, for a more complex pane. That way I let the layout engine calculate the appropriate amount of space to reserve.