Dynamisches Hinzufügen von Elementen zu einem GridPane mit fester Größe in JavaFX

Ich möchte in JavaFX ein Raster mit einer unterschiedlichen Anzahl von Rechtecken anzeigen. Es ist wichtig, dass die Größe dieses Rasters nicht geändert werden kann.

Ich habe das gewähltGridPane Layout. Ich füge dynamisch hinzujavafx.scene.shape.Rectangle dazu. So sieht mein Raster mit 2 Zeilen und 4 Spalten aus.

Beim Ändern der Größe möchte ich, dass es die gleiche Gesamtform beibehält, d. H. JedeRectangle die gleiche Größe haben und eine horizontale und vertikale Lücke zwischen meinenRectangles.

Folgendes bekomme ich jedoch mit einem 4x4-Gitter:

Die Probleme sind:

Die letzte Zeile und die letzte Spalte haben nicht die gleiche Größe wie der Rest derRectangles.Die Lücken sind verschwunden.

Hier ist mein Code, der für die Aktualisierung der Anzeige verantwortlich ist:

public void refreshConstraints() {
    getRowConstraints().clear();
    getColumnConstraints().clear();

    for (int i = 0; i < nbRow; i++) {
        RowConstraints rConstraint = new RowConstraints();
        // ((nbRow - 1) * 10 / nbRow) = takes gap into account (10% of height)
        rConstraint.setPercentHeight(100 / nbRow - ((nbRow - 1) * 10 / nbRow));
        getRowConstraints().add(rConstraint);
    }

    for (int i = 0; i < nbColumn; i++) {
        ColumnConstraints cConstraint = new ColumnConstraints();
        cConstraint.setPercentWidth(100 / nbColumn - ((nbColumn - 1) * 10 / nbColumn));
        getColumnConstraints().add(cConstraint);
    }

}

Verwendung dersetFillWidth undsetHgrow liefert auch kein ergebnis, die lücke bleibt zwischen meinenRectangles, aber dieRectangleDie Größe von s wird nicht geändert und sie überlappen den Rest meiner GUI-Elemente.

BEARBEITEN: MCVE-Code:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class DynamicGrid extends Application {

    //Class containing grid (see below)
    private GridDisplay gridDisplay;

    @Override
    public void start(Stage primaryStage) {

        //Represents the grid with Rectangles
        gridDisplay = new GridDisplay(400, 200);

        //Fields to specify number of rows/columns
        TextField rowField = new TextField();
        TextField columnField = new TextField();
        //Function to set an action when text field loses focus
        buildTextFieldActions(rowField, columnField);
        HBox fields = new HBox();
        fields.getChildren().add(rowField);
        fields.getChildren().add(new Label("x"));
        fields.getChildren().add(columnField);

        BorderPane mainPanel = new BorderPane();
        mainPanel.setLeft(gridDisplay.getDisplay());
        mainPanel.setBottom(fields);

        Scene scene = new Scene(mainPanel);
        primaryStage.setTitle("Test grid display");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    private void buildTextFieldActions(final TextField rowField, final TextField columnField) {
        rowField.focusedProperty().addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                if (!t1) {
                    if (!rowField.getText().equals("")) {
                        try {
                            int nbRow = Integer.parseInt(rowField.getText());
                            gridDisplay.setRows(nbRow);
                            gridDisplay.updateDisplay();
                        } catch (NumberFormatException nfe) {
                            System.out.println("Please enter a valid number.");
                        }
                    }
                }
            }
        });

        columnField.focusedProperty().addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                if (!t1) {
                    if (!columnField.getText().equals("")) {
                        try {
                            int nbColumn = Integer.parseInt(columnField.getText());
                            gridDisplay.setColumns(nbColumn);
                            gridDisplay.updateDisplay();
                        } catch (NumberFormatException nfe) {
                            System.out.println("Please enter a valid number.");
                        }
                    }
                }
            }
        });
    }

    //Class responsible for displaying the grid containing the Rectangles
    public class GridDisplay {

        private GridPane gridPane;
        private int nbRow;
        private int nbColumn;
        private int width;
        private int height;
        private double hGap;
        private double vGap;

        public GridDisplay(int width, int height) {
            this.gridPane = new GridPane();
            this.width = width;
            this.height = height;
            build();
        }

        private void build() {
            this.hGap = 0.1 * width;
            this.vGap = 0.1 * height;
            gridPane.setVgap(vGap);
            gridPane.setHgap(hGap);
            gridPane.setPrefSize(width, height);
            initializeDisplay(width, height);
        }

        //Builds the first display (correctly) : adds a Rectangle for the number
        //of rows and columns
        private void initializeDisplay(int width, int height) {
            nbRow = height / 100;
            nbColumn = width / 100;

            for (int i = 0; i < nbColumn; i++) {
                for (int j = 0; j < nbRow; j++) {
                    Rectangle rectangle = new Rectangle(100, 100);
                    rectangle.setStroke(Paint.valueOf("orange"));
                    rectangle.setFill(Paint.valueOf("steelblue"));
                    gridPane.add(rectangle, i, j);

                }
            }
        }

        //Function detailed in post
        //Called in updateDisplay()
        public void refreshConstraints() {
            gridPane.getRowConstraints().clear();
            gridPane.getColumnConstraints().clear();
            for (int i = 0; i < nbRow; i++) {
                RowConstraints rConstraint = new RowConstraints();
                rConstraint.setPercentHeight(100 / nbRow - ((nbRow - 1) * 10 / nbRow));
                gridPane.getRowConstraints().add(rConstraint);
            }

            for (int i = 0; i < nbColumn; i++) {
                ColumnConstraints cConstraint = new ColumnConstraints();
                cConstraint.setPercentWidth(100 / nbColumn - ((nbColumn - 1) * 10 / nbColumn));
                gridPane.getColumnConstraints().add(cConstraint);
            }

        }

        public void setColumns(int newColumns) {
            nbColumn = newColumns;
        }

        public void setRows(int newRows) {
            nbRow = newRows;
        }

        public GridPane getDisplay() {
            return gridPane;
        }

        //Function called when refreshing the display
        public void updateDisplay() {
            Platform.runLater(new Runnable() {

                @Override
                public void run() {
                    //The gridpane is cleared of the previous children
                    gridPane.getChildren().clear();

                    //A new rectangle is added for row*column
                    for (int i = 0; i < nbColumn; i++) {
                        for (int j = 0; j < nbRow; j++) {
                            Rectangle rectangle = new Rectangle(100, 100);
                            rectangle.setStroke(Paint.valueOf("orange"));
                            rectangle.setFill(Paint.valueOf("steelblue"));
                            gridPane.add(rectangle, i, j);
                        }
                    }
                    //Call to this function to update the grid's constraints
                    refreshConstraints();
                }
            });

        }

    }

}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage