当前位置: 首页 > 知识库问答 >
问题:

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

凌清夷
2023-03-14

我想在JavaFX中显示一个包含不同数量矩形的网格。重要的是不能调整此网格的大小。

我选择了GridPane布局。我动态地将javafx.scene.shape.rectangle添加到它中。下面是我的网格看起来像2行4列。

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

    null
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);
    }

}
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();
                }
            });

        }

    }

}

共有1个答案

公孙巴英
2023-03-14

TilePane似乎比GridPane更适合这个用例。

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.");
                    }
                }
            }
        });
    }
}
 类似资料:
  • 我对JavaFX相对较新,我很困惑为什么我下面的代码没有产生预期的结果,即添加到网格中的标签。 我想做的是运行一个测试,将JavaFX标签添加到我的FXML GridPane,因为我想在不久的将来构建一个方法,允许用户选择一个文件,然后在用户选择文件时生成一个标签并将该标签添加到GridPane。 提前感谢, 代码: FXML代码是一个标准文件,其中定义了一个网格窗格,上面列出了fx:id。

  • 我需要创建可以动态变化棋盘游戏。 它的大小可以是5x5、6x6、7x7或8x8。 我将JavaFX与NetBeans和Scene builder一起用于GUI。 对于GridPane中的每个单元格,我将添加单元格编号的StackPane+label: 我在网上搜索,但没有找到与我相同的问题。 唯一与我相似的问题是在这里找到的: 在JavaFX中动态地向固定大小的GridPane中添加元素 但是他的

  • 我是JavaFX的新手,目前我试图构建一个小型聊天窗口。为此,我为我的Listview获得了以下自定义单元格布局。 网格 我使用外部HBox,所以我可以像whatsapp一样对齐消息。。。(左右对齐)。在我的GridPane中,我得到了两列,消息(标签)在左侧,其他一些随机的东西在右侧(时间戳,一些小图标)。现在我需要的是:GridPane/左列/标签的高度应该根据文本消息的长度动态地增长/收缩。

  • 如何使用< code>GridPane上的权重设置行/列大小? 例如,如果我想要五行,其中三行是未知的固定大小,一行占用剩余空间的三分之一,另一行占用剩余空间的三分之二(见下图),我该如何实现呢? 我查看了使用,其中两个有但这只允许平均共享剩余空间。 我尝试使用百分比,因为我在文档< code >中看到,如果widthPercent(或heightPercent)值的总和大于100,这些值将被视为

  • 问题内容: 我是Groovy的新手,尽管阅读了许多有关此的文章和问题,但我仍然不清楚发生了什么。到目前为止,据我了解,当您在Groovy中创建新数组时,底层类型是Java ArrayList。这意味着它应该可调整大小,您应该能够将其初始化为空,然后通过add方法动态添加元素,如下所示: 编译,但是在运行时失败:方法的无签名:[LMyType; .add()适用于参数类型:(MyType)值:[My

  • 我正在尝试使用两列创建一个具有特定布局的窗口,但我不能完全按照我想要的方式工作。 首先,一些简化的示例代码: 以下是我想要的: 微调器和按钮应使用所有可用宽度 我试着使用各种各样的限制,但我无法让一切都正常工作。我认为我发现的主要问题是,在让微调器使用可用宽度后,它们在缩小窗口时拒绝收缩。 我正在Linux中使用Oracle JDK 1.8.0\u 60。