在JavaFX中将元素动态添加到固定大小的GridPane

时间:2014-04-24 15:12:59

标签: java javafx gridpane

我想在JavaFX中显示包含各种矩形的网格。重要的是此网格无法调整大小。

我选择了GridPane布局。我动态添加javafx.scene.shape.Rectangle。这是我的网格在2行和4列中的样子。

Grid 4x2

调整大小后,我希望它保持相同的整体形状,也就是说每个Rectangle具有相同的大小,并在Rectangle s之间保持水平和垂直间隙。

然而,这是我用4x4网格得到的: enter image description here

问题是:

  • 最后一行和最后一列与{​​{1}}的其余部分的大小不同。
  • 差距已经消失。

这是我负责刷新显示的代码:

Rectangle

使用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); } } setFillWidth也没有产生任何结果,差距保持在我的setHgrow之间,但Rectangle s未调整大小,重叠其余的GUI元素。


编辑:MCVE代码:

Rectangle

2 个答案:

答案 0 :(得分:10)

似乎TilePane比GridPane更适合此用例。

2by4 3by2

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

// java 8 code
public class DynamicTiles extends Application {

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

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

        private static final double ELEMENT_SIZE = 100;
        private static final double GAP = ELEMENT_SIZE / 10;

        private TilePane tilePane = new TilePane();
        private Group display = new Group(tilePane);
        private int nRows;
        private int nCols;

        public GridDisplay(int nRows, int nCols) {
            tilePane.setStyle("-fx-background-color: rgba(255, 215, 0, 0.1);");
            tilePane.setHgap(GAP);
            tilePane.setVgap(GAP);
            setColumns(nCols);
            setRows(nRows);
        }

        public void setColumns(int newColumns) {
            nCols = newColumns;
            tilePane.setPrefColumns(nCols);
            createElements();
        }

        public void setRows(int newRows) {
            nRows = newRows;
            tilePane.setPrefRows(nRows);
            createElements();
        }

        public Group getDisplay() {
            return display;
        }

        private void createElements() {
            tilePane.getChildren().clear();
            for (int i = 0; i < nCols; i++) {
                for (int j = 0; j < nRows; j++) {
                    tilePane.getChildren().add(createElement());
                }
            }
        }

        private Rectangle createElement() {
            Rectangle rectangle = new Rectangle(ELEMENT_SIZE, ELEMENT_SIZE);
            rectangle.setStroke(Color.ORANGE);
            rectangle.setFill(Color.STEELBLUE);

            return rectangle;
        }

    }

    @Override
    public void start(Stage primaryStage) {

        //Represents the grid with Rectangles
        gridDisplay = new GridDisplay(2, 4);

        //Fields to specify number of rows/columns
        TextField rowField = new TextField("2");
        TextField columnField = new TextField("4");

        //Function to set an action when text field loses focus
        buildTextFieldActions(rowField, columnField);

        HBox fields = new HBox(10);
        fields.getChildren().add(rowField);
        fields.getChildren().add(new Label("x"));
        fields.getChildren().add(columnField);

        BorderPane mainPanel = new BorderPane();
        mainPanel.setCenter(gridDisplay.getDisplay());
        mainPanel.setTop(fields);

        Scene scene = new Scene(mainPanel, 1000, 800);
        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((ov, t, t1) -> {
            if (!t1) {
                if (!rowField.getText().equals("")) {
                    try {
                        int nbRow = Integer.parseInt(rowField.getText());
                        gridDisplay.setRows(nbRow);
                    } catch (NumberFormatException nfe) {
                        System.out.println("Please enter a valid number.");
                    }
                }
            }
        });

        columnField.focusedProperty().addListener((ov, t, t1) -> {
            if (!t1) {
                if (!columnField.getText().equals("")) {
                    try {
                        int nbColumn = Integer.parseInt(columnField.getText());
                        gridDisplay.setColumns(nbColumn);
                    } catch (NumberFormatException nfe) {
                        System.out.println("Please enter a valid number.");
                    }
                }
            }
        });
    }
}

答案 1 :(得分:3)

非常感谢您的回答。 TilePane确实更容易使用,虽然你所写的并不能完全回答我的问题。

我希望有一个窗格,其中孩子会调整大小,而不是窗格本身。似乎设置maxSizeprefSize没有任何效果。

编辑:我设法在我的Property类中使用两个JavaFX GridDisplay,对应于网格的固定高度和宽度:

public class GridDisplay {
    private ReadOnlyDoubleProperty heightProperty;
    private ReadOnlyDoubleProperty widthProperty;

    ...
}

然后我将这些成员分配给构造函数中所需固定大小的值。网格内部子项的大小对应于网格高度和宽度的一小部分,具体取决于行数和列数。这是我updateDisplay()的样子:

public void updateDisplay() {
    gridPane.getChildren().clear();
    for (int i = 0; i < nbColumn; i++) {
        for (int j = 0; j < nbRow; j++) {
            Rectangle rectangle = new Rectangle(100, 100);
            //Binding the fraction of the grid size to the width
            //and heightProperty of the child
            rectangle.widthProperty().bind(widthProperty.divide(nbColumn));
            rectangle.heightProperty().bind(heightProperty.divide(nbRow));
            gridPane.add(rectangle, i, j);
         }
    }
}