im trying to add multiply VBox to a gridpane (called refPane in the following codesnippet) which is inside a scrollpane.
int columnIndex = 0;
int rowIndex = 0;
int boxWidth = windowWidth/ITEMS_PER_ROW;
int boxHeight = windowHeight/ITEMS_PER_COLUMN;
for(int i=0; i<items.size(); i++){
VBox vBox = new VBox();
vBox.setPrefWidth(boxWidth);
vBox.setPrefHeight(boxHeight);
Label label1 = new Label();
label1.setText("ImgPlaceholder");
label1.setPrefWidth(boxWidth);
label1.setPrefHeight(boxHeight / 100 * 70);
vBox.getChildren().add(label1);
Label label2 = new Label();
label2.setText("Description");
label2.setPrefWidth(boxWidth);
label2.setPrefHeight(boxHeight / 100 * 30);
label2.setPadding(new Insets(0,0,0, 10));
vBox.getChildren().add(label2);
refPane.add(vBox, columnIndex, rowIndex);
if(columnIndex != 0 && columnIndex % GAMES_PER_ROW == 0){
rowIndex++;
columnIndex = 0;
}else {
columnIndex++;
}
It adds no more then ITEMS_PER_ROW Vboxes in one row and continues in the next row. Also there should be no more rows then ITEMS_PER_COLUM visible.
The problem is, if I add more then ITEMS_PER_ROW * ITEMS_PER_COLUMN to the grid, instead ob beeing scrollable, the vboxes just get smaller in size.
Any Ideas? Thanks in advance.
Chances are javafx is prioritizing shrinking the VBox's over expanding your grid pane. Try setting the minHeight of each VBox, to be equal to its prefHeight to keep them from shrinking vertically.
Related
When I run this, it creates only one button. I'm trying to create a gridPane of buttons, 10x10 and when a button is clicked it would send the row column(x,y) coordinates to another class which would handle its purpose (a battleship game)
Button button[][] = new Button[10][10];
public static int rows, columns, gridSize;
for (rows = 0; rows < 10; rows++) {
for (columns = 0; columns < 10; columns++) {
button[rows][columns] = new Button();
button[rows][columns].setStyle("-fx-background-color: red");
button[rows][columns].setPrefSize(50, 50);
button[rows][columns].setOnMouseClicked(new clickEvents(rows, columns));
//no setters, directly passed rows and cols to clickEvents Class
tileGrid.getChildren().add(button[rows][columns]); //adds buttons to the tile grid
}
}
container.getChildren().addAll(tileGrid);
ScrollPane scrollPane = new ScrollPane(container);
primaryStage.setScene(new Scene(scrollPane));
primaryStage.show();
You aren't telling the system where to put the button in the GridPane.
Use gridPane.add(child, colIndex, rowIndex):
tileGrid.add(button[row][column], column, row);
I fixed spelling and removed plurality (trailing 's') from the row, column variables.
Alternately, you could set constraints on the node in the GridPane:
tileGrid.getChildren().add(button[row][column]);
GridPane.setConstraints(button[row][column], column, row);
But it is a less verbose to use the add method which specifies the constraints in initial add parameters (as in the prior example).
Without any constraints on the nodes added as children to the grid, all the children will be located at the default 0,0 grid location (all stacked on top of each other).
This line is the one giving you issues
tileGrid.getChildren().add(button[rows][columns]);
This is due to the fact that you are incorrectly adding your buttons. If you try something like
tileGrid.add(
button[rows][columns], // Specific node in the array
columns, // Set the specific column
rows // Set the specific row
); //adds buttons to the tile grid
it should work here is the full example code
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button button[][] = new Button[10][10];
int rows, columns, gridSize;
GridPane tileGrid = new GridPane();
for (rows = 0; rows < 10; rows++) {
for (columns = 0; columns < 10; columns++) {
button[rows][columns] = new Button();
button[rows][columns].setStyle("-fx-background-color: red");
button[rows][columns].setPrefSize(50, 50);
//button[rows][columns].setOnMouseClicked(new clickEvents(rows, columns));
//no setters, directly passed rows and cols to clickEvents Class
tileGrid.add(
button[rows][columns], // Specific node in the array
columns, // Set the specific column
rows // Set the specific row
); //adds buttons to the tile grid
}
}
ScrollPane scrollPane = new ScrollPane(new VBox(tileGrid));
primaryStage.setScene(new Scene(scrollPane));
primaryStage.show();
}
}
EDIT: 2 Min too slow but I'm going to leave it here so he can see the example if he needs it
I am creating a "threes" clone for my assignment and one of the properties was to have a dynamically sizable GridPane depending on the number of columns and rows, how can I achieve this?
I've looked at adding ColumnConstraints as well as RowConstraints, given them a percentile width of the total GridPane size divided by the number of columns:
// width = total / number of columns
// height = total / number of rows
In Scene Builder the GridPane has by default a 4x4 size; these elements seem to resize just fine but when say a 4x5 size is loaded it seems to only want to show 4x4 (styled) and the other remaining tiles look "weird".
Here's what it looks like: https://imgur.com/gallery/Qv1oWZb
// width = total / number of columns
// height = total / number of rows
gridPane.setGridLinesVisible(false);
gridPane.setAlignment(Pos.TOP_LEFT);
gridPane.getChildren().clear();
RowConstraints rowConstraint = new RowConstraints();
rowConstraint.setPercentHeight(300 / game.getBoardSizeY());
ColumnConstraints colConstraint = new ColumnConstraints();
colConstraint.setPercentWidth(350 / game.getBoardSizeX());
for(int x= 0; x < game.getBoardSizeX(); x++) {
gridPane.getColumnConstraints().add(colConstraint);
for(int y = 0; y < game.getBoardSizeY(); y++) {
gridPane.getRowConstraints().add(rowConstraint);
Tile tile = game.getBoard().getPos(x, y);
Pane pane = new Pane();
String lblText = "";
String itemClass = "";
if(tile.getValue() != 0) {
lblText = String.valueOf(tile.getValue());
}
int tileVal = tile.getValue();
if(tileVal == 1) {
itemClass = "blueTile";
}else if (tileVal == 2) {
itemClass = "redTile";
}else if (tileVal >= 3 ) {
itemClass = "whiteTile";
}else {
itemClass = "defaultTile";
}
Label lblVal = new Label(lblText);
pane.getStyleClass().addAll("tile", itemClass);
lblVal.layoutXProperty().bind(pane.widthProperty().subtract(lblVal.widthProperty()).divide(2));
pane.getChildren().add(lblVal);
gridPane.add(pane, x, y);
}
}
I expect it to fill my entire GridPane accordingly but instead it acts up and shows me the result shown in the images.
Edit:
I've gotten it to work however when I have differentiating rows (like 4x5 for example) it doesn't quite work out the sizing yet.
gridPane.setGridLinesVisible(false);
gridPane.setAlignment(Pos.TOP_LEFT);
gridPane.getChildren().clear();
gridPane.getChildren().removeAll();
gridPane.getColumnConstraints().clear();
gridPane.getRowConstraints().clear();
RowConstraints rowConstraint = new RowConstraints();
rowConstraint.setPercentHeight(350 / game.getBoardSizeY());
ColumnConstraints colConstraint = new ColumnConstraints();
colConstraint.setPercentWidth(300 / game.getBoardSizeX());
for(int x= 0; x < game.getBoardSizeX(); x++) {
gridPane.getColumnConstraints().add(colConstraint);
gridPane.getRowConstraints().add(rowConstraint);
for(int y = 0; y < game.getBoardSizeY(); y++) {
Tile tile = game.getBoard().getPos(x, y);
Pane pane = new Pane();
String lblText = "";
String itemClass = "";
if(tile.getValue() != 0) {
lblText = String.valueOf(tile.getValue());
}
int tileVal = tile.getValue();
if(tileVal == 1) {
itemClass = "blueTile";
}else if (tileVal == 2) {
itemClass = "redTile";
}else if (tileVal >= 3 ) {
itemClass = "whiteTile";
}else {
itemClass = "defaultTile";
}
Label lblVal = new Label(lblText);
pane.getStyleClass().addAll("tile", itemClass);
lblVal.layoutXProperty().bind(pane.widthProperty().subtract(lblVal.widthProperty()).divide(2));
pane.getChildren().add(lblVal);
gridPane.add(pane, x, y);
}
}
If I understood correctly, you want the rows and columns to resize so that all columns have the same width and all rows have the same height. If that's correct, this sounds wrong:
I've looked at adding columnConstraints as well as rowConstraints, given them a percentile width of the total gridpane size devided by the number of columns
// width = total / number of columns
// height = total / number of rows
The percentile width/height is a relative measurement. You don't wan't to calculate that based on the current width/height. For instance, if you had 4 rows you'd have each row be 25% of the height.
That said, I don't believe you need to mess around with the width or height settings on the constraints. Just set the RowConstraints.vgrow and ColumnConstraints.hgrow properties to Priority.ALWAYS. Here's an example:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setAlignment(Pos.CENTER);
root.setGridLinesVisible(true);
for (int col = 0; col < 5; col++) {
root.getColumnConstraints()
.add(new ColumnConstraints(-1, -1, -1, Priority.ALWAYS, HPos.CENTER, false));
for (int row = 0; row < 3; row++) {
if (col == 0) {
root.getRowConstraints()
.add(new RowConstraints(-1, -1, -1, Priority.ALWAYS, VPos.CENTER, false));
}
root.add(new Label(String.format("(%d,%d)", row, col)), col, row);
}
}
primaryStage.setScene(new Scene(root, 500, 300));
primaryStage.show();
}
}
I try to align the vertical scroll position of two javafx.scene.control.ScrollPanes via
sp1.vvalueProperty().bindBidirectional(sp2.vvalueProperty());
The problem is that one of these ScrollPanes may have a horizontal scroll bar. So the more I scroll down the ScrollPanes, the more they get misaligned (see screenshot). How can I handle this?
It's impossible to do this with 2 ScrollPanes and contents of equal height unless you display the scrollbar in both ScrollPanes:
Consider the case where the content fits the viewport of the left ScrollPane exactly. The viewPort of the right ScrollPane can be scrolled by the ScrollBar height. Modifying the left ScrollPane is not possible.
Since the expected result seems to be some kind of scale, you could simply use a Pane with a child you apply transformY to and a clip. The formula to calculate the pixel to be placed at the top, use
top = vvalue * (contentHeight - viewportHeight)
Example
private static Label createLabel(int num, boolean mark) {
Label label = new Label(Integer.toString(num));
label.setPrefSize(50, 50);
label.setMaxSize(Double.MAX_VALUE, Region.USE_PREF_SIZE);
label.setStyle(mark ? "-fx-background-color: #FFFFFF" : "-fx-background-color: #BBBBBB;");
return label;
}
#Override
public void start(Stage primaryStage) throws Exception {
VBox scale = new VBox();
scale.setMinHeight(Region.USE_PREF_SIZE);
GridPane content = new GridPane();
for (int i = 0; i < 40; i++) {
boolean b = ((i % 2) == 0);
scale.getChildren().add(createLabel(i, !b));
for (int j = 0; j < 10; j++) {
content.add(createLabel(i * 10 + j, b), j, i);
}
}
AnchorPane scaleContainer = new AnchorPane(scale);
scaleContainer.setMinWidth(30);
scaleContainer.setMinHeight(0);
AnchorPane.setLeftAnchor(scale, 0d);
AnchorPane.setRightAnchor(scale, 0d);
Rectangle clip = new Rectangle();
scaleContainer.setClip(clip);
clip.widthProperty().bind(scaleContainer.widthProperty());
clip.heightProperty().bind(scaleContainer.heightProperty());
ScrollPane scroll = new ScrollPane(content);
scale.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
double contentHeight = content.getHeight();
double viewportHeight = scroll.getViewportBounds().getHeight();
if (contentHeight <= viewportHeight) {
return 0d;
} else {
return -scroll.getVvalue() * (contentHeight - viewportHeight);
}
}, scroll.viewportBoundsProperty(), scroll.vvalueProperty(), content.heightProperty()));
HBox root = new HBox(scaleContainer, scroll);
root.setPadding(new Insets(10));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
I am currently working on a project, and I cannot find just any solution. I want a Gridpane row height to be dynamically counted from the width of one specific column inside that row. The whole Gridpane must be resizable and the rest of the available space should take another row below so the aspect ratio of that one cell is preserved according to the element inside that cell. Any ideas boys?
click for a pic
public class GridPaneControl extends GridPane {
private int index;
private Label startLabel;
private Label endLabel;
private HBox inputCellsContainer;
private HBox outputCellsContainer;
private Button inputOutputNextButton;
private Button inputOutputPreviousButton;
public GridPaneControl() {
setGridLinesVisible(true);
initialization();
ColumnConstraints cc0 = new ColumnConstraints();
cc0.setMaxWidth(Double.MAX_VALUE);
cc0.setHgrow(Priority.NEVER);
ColumnConstraints cc1 = new ColumnConstraints();
cc1.setMaxWidth(Double.MAX_VALUE);
ColumnConstraints cc2 = new ColumnConstraints();
cc2.setMaxWidth(Double.MAX_VALUE);
cc2.setHgrow(Priority.NEVER);
RowConstraints rc0 = new RowConstraints();
rc0.setVgrow(Priority.ALWAYS);
rc0.setFillHeight(false);
rc0.setMaxHeight(Double.MAX_VALUE);
RowConstraints rc1 = new RowConstraints();
rc1.setVgrow(Priority.ALWAYS);
rc1.setFillHeight(false);
rc1.setMaxHeight(Double.MAX_VALUE);
RowConstraints rc2 = new RowConstraints();
rc2.setVgrow(Priority.NEVER);
RowConstraints rc3 = new RowConstraints();
rc3.setVgrow(Priority.ALWAYS);
getColumnConstraints().addAll(cc0, cc1, cc2);
getRowConstraints().addAll(rc0, rc1, rc2, rc3);
}
private void initialization() {
inputCellsContainer = new HBox(0);
outputCellsContainer = new HBox(0);
GridPane.setValignment(inputCellsContainer, VPos.BOTTOM);
GridPane.setValignment(outputCellsContainer, VPos.TOP);
inputOutputPreviousButton = new Button("<<");
inputOutputPreviousButton.maxWidth(Double.MAX_VALUE);
GridPane.setHgrow(inputOutputPreviousButton, Priority.NEVER);
GridPane.setVgrow(inputOutputPreviousButton, Priority.NEVER);
GridPane.setMargin(inputOutputPreviousButton, new Insets(5));
inputOutputNextButton = new Button(">>");
inputOutputNextButton.maxWidth(Double.MAX_VALUE);
GridPane.setHgrow(inputOutputNextButton, Priority.NEVER);
GridPane.setVgrow(inputOutputNextButton, Priority.NEVER);
GridPane.setMargin(inputOutputNextButton, new Insets(5));
for (int i = 0; i < 32; i++) {
InputOutputCell cellIn = new InputOutputCell(String.format("%02X", i), Color.AQUA, 0);
InputOutputCell cellOut = new InputOutputCell(String.format("%02X", i), Color.BEIGE, 1);
HBox.setHgrow(cellIn, Priority.ALWAYS);
HBox.setHgrow(cellOut, Priority.ALWAYS);
inputCellsContainer.getChildren().add(cellIn);
outputCellsContainer.getChildren().add(cellOut);
}
GridPane.setHgrow(inputCellsContainer, Priority.ALWAYS);
GridPane.setHgrow(outputCellsContainer, Priority.ALWAYS);
GridPane.setVgrow(inputCellsContainer, Priority.ALWAYS);
GridPane.setVgrow(outputCellsContainer, Priority.ALWAYS);
startLabel = new Label("0");
endLabel = new Label("31");
GridPane.setHalignment(startLabel, HPos.LEFT);
GridPane.setHalignment(endLabel, HPos.RIGHT);
this.add(inputOutputPreviousButton, 0, 0, 1, 2);
this.add(inputCellsContainer, 1, 0);
this.add(outputCellsContainer, 1, 1);
this.add(inputOutputNextButton, 2, 0, 1, 2);
this.add(startLabel, 1, 2);
this.add(endLabel, 1, 2);
}
public int getIndex() {
return index;
}
private class InputOutputCell extends StackPane {
#FXML
Text text;
#FXML
Rectangle rectangle;
public InputOutputCell(String text, Color color, int type) {
setMinSize(0, 0);
this.text = new Text(text);
rectangle = new Rectangle();
if (type == 0) {
rectangle.widthProperty().bind(inputCellsContainer.widthProperty().divide(32));
rectangle.heightProperty().bind(inputCellsContainer.widthProperty().divide(32));
} else {
rectangle.widthProperty().bind(outputCellsContainer.widthProperty().divide(32));
rectangle.heightProperty().bind(outputCellsContainer.widthProperty().divide(32));
}
rectangle.maxWidth(Double.MAX_VALUE);
rectangle.maxHeight(Double.MAX_VALUE);
rectangle.setArcHeight(10);
rectangle.setArcWidth(10);
rectangle.setFill(color);
rectangle.setStroke(Color.BLACK);
getChildren().addAll(rectangle, this.text);
}
public void setText(String text) {
this.text.setText(text);
}
public String getText() {
return this.text.getText();
}
}
}
I want cells 1,0 and 1,1 to be resizable and clearly by increasing their width the height of row 0 and 1 should not be increasing equally. If there should be any height left I want the row 3 to take it because row 2 should not grow to height at all.
You did a fair bit of explanation (which is good) but it is complex enough to make me read 10 times, and I think I understood 70% of it. The most puzzling part is this line:
the rest of the available space should take another row below so the aspect ratio of that one cell is preserved according to the element inside that cell.
Not sure which "cell" you are referrring to, and what you mean by keeping aspect ratio.
Now for the actual answer, I think the most obvious one that I can see is that you have given rows 0 and 1 ALWAYS priority for VGrow.
You have 3 rows that has ALWAYS VGrow, and what the GridPane will do is to give all children to whatever space that they preferred to have, then distribute all the "leftover" spaces to rows with ALWAYS. That is why the 3 gaps in your image has the same height.
I'm newer to JavaFX and I'm attempting to make a checkerboard. I first want to start out by making a gridpane of squares that fill with random colors based on
an array. I'm not sure why, but the squares aren't filling the rest of the grid. I'd also like to use constraints to set the grid height and width.
int rowNum = 10;
int colNum = 10;
int gridHeight = 10;
int gridWidth = 10;
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
//grid.getColumnConstraints().add(new ColumnConstraints(gridWidth));
//grid.getRowConstraints().add(new RowConstraints(gridHeight));
Random rand = new Random();
Color[] colors = {Color.BLACK, Color.BLUE, Color.GREEN, Color.RED};
int n = rand.nextInt(4)+1;
for(int row = 0; row < rowNum; row++){
for(int col = 0; col < colNum; col++){
Rectangle rec = new Rectangle();
rec.setWidth(2);
rec.setHeight(2);
rec.setFill(colors[n]);
GridPane.setRowIndex(rec, row);
GridPane.setColumnIndex(rec, col);
grid.getChildren().addAll(rec);
}
}
Scene scene = new Scene(grid, 350, 250);
primaryStage.setTitle("Grid");
primaryStage.setScene(scene);
primaryStage.show();
}
Only one square appears on the top left.
Why is this the case?
You need to move the random number generation step inside the two loops so that you're not using the same color that has been set once before entering the loop. Also, you don't need the plus 1 on that random number generator. The allowed indices are 0-3. When you ask for the nextInt() and input a 4, that's exclusive which means 4 will never be picked (which is what you need for the Color array).
Your code should look like this:
for (int row = 0; row < rowNum; row++) {
for (int col = 0; col < colNum; col++) {
int n = rand.nextInt(4);
Rectangle rec = new Rectangle();
rec.setWidth(2);
rec.setHeight(2);
rec.setFill(colors[n]);
GridPane.setRowIndex(rec, row);
GridPane.setColumnIndex(rec, col);
grid.getChildren().addAll(rec);
}
}