I'm trying to make a JavaFX GridPane filled with buttons. I have an ArrayList with objects, and for each of those objects, a button needs to be made. However, the size of the ArrayList is not always the same. Therefore, I have so far made this code:
The JavaFX GridPane part:
<AnchorPane fx:id="gridAnchorPane" minHeight="120.0" minWidth="450.0" prefHeight="120.0" prefWidth="550.0">
<GridPane fx:id="peopleGridPane" hgap="5.0" layoutX="98.0" layoutY="43.0" translateX="1.0" translateY="1.0" translateZ="1.0" vgap="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
</GridPane>
</AnchorPane>
As you can see, I have zero rows and columns, since I intend on making those a dynamic amount and size.
The controller part for making the buttons:
int GRIDWIDTH = //how many buttons are to fit in one row
for (int i = 0; i < people.size(); i++){
peopleGridPane.add(personButton(people.get(i).getName()), i % GRIDWIDTH, i / GRIDWIDTH);
}
private Button personButton(String name) {
button.setPrefSize(
peopleGridPane.getWidth() / GRIDWIDTH,
peopleGridPane.getHeight() / (people.size() / GRIDWIDTH)
);
Using this method, I get two problems.
I am at a loss, so all suggestions are welcome.
For problem 2, I have made a simple recreation:
Main:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
private int GRIDWIDTH = 3;
@FXML
@Override
public void initialize(URL location, ResourceBundle resources) {
refresh();
}
private void refresh() {
for (int i = 0; i < people.size(); i++) {
Button button = new Button(people.get(i).getName());
button.setPrefSize(
grid.getWidth() / GRIDWIDTH,
grid.getHeight() / (people.size() / GRIDWIDTH)
);
button.setOnAction(event -> refresh());
grid.add(button, i % GRIDWIDTH, i / GRIDWIDTH);
}
}
public Controller() {
people = new ArrayList<>();
people.add(new Person("P1"));
people.add(new Person("P2"));
people.add(new Person("P3"));
people.add(new Person("P4"));
}
.fxml file:
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="201.0" prefWidth="240.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<items>
<Pane prefHeight="200.0" prefWidth="200.0" />
<GridPane fx:id="grid" alignment="center" hgap="10" vgap="10">
</GridPane>
</items>
</SplitPane>
Before clicking a button.
After clicking a button.
I have discovered both of the solutions to the problems.
Clipping into the border
The reason the button clipped into the button was because of the fact that I divide an int a by int b, when b > a, resulting in 0, since both are ints. When I cast the numbers to doubles, the resulting number is something like 0.3333 or 0.66666, therefore being more than 0 and fixing the issue.
Buttons width being 0
The issue here is that when I called refresh()
the first time, all elements on the screen did not yet "exist". That is, they did exist, but they hadn't been put up on the screen yet, which made their width and height be 0.0 or -1.0. However, if you specify a specific height or width, e.g. a specified or minimum width/height, you can call upon those attributes if the height or width of a window < 1. This way, it still won't look very good when you resize the window since the width and height are at that point just a static double, but at least it's readable.