在JavaFX中将元素动态添加到固定大小的GridPane [英] Dynamically add elements to a fixed-size GridPane in JavaFX

查看:2402
本文介绍了在JavaFX中将元素动态添加到固定大小的GridPane的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to display a grid containing a various number of rectangles in JavaFX. It is important that this grid cannot be resized.

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

I chose the GridPane layout. I dynamically add javafx.scene.shape.Rectangle to it. Here's how my grid looks like with 2 rows and 4 columns.

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

Upon resizing, I would like it to keep the same overall shape, that is to say each Rectangle having the same size and keeping an horizontal and vertical gaps between my Rectangles.

但是,这是我用4x4网格得到的:

However, here's what I get with a 4x4 grid:

问题是:


  • 最后一行和最后一列与其余部分的大小不同矩形 s。

  • 差距已经消失。

  • The last row and last column do not have the same size as the rest of the Rectangles.
  • The gaps have disappeared.

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

Here is my code responsible for refreshing the display:

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之间,但 Rectangle 未调整大小,它们与我的其余GUI元素重叠。

Using the setFillWidth and setHgrow yields no result either, the gap is kept between my Rectangles, but the Rectangles aren't resized and they overlap the rest of my GUI elements.

编辑:MCVE代码:

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

        }

    }

}


推荐答案

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

Thanks a lot for your answer. TilePanes are indeed a lot easier to use, although what you've written does not completely answer my question.

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

I wanted to have a pane in which the children would resize, and not the pane itself. It seems setting the maxSize and prefSize doesn't have any effect.

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

EDIT: I managed to do it using two JavaFX Property in my GridDisplay class, corresponding to the fixed height and width of my grid:

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

    ...
}

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

Then I assign to these members the values corresponding to the desired fixed size in the constructor. The size of the children inside the grid correspond to a fraction of the height and width of the grid, depending on the number of rows and columns. Here's what my updateDisplay() looks like:

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

这篇关于在JavaFX中将元素动态添加到固定大小的GridPane的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆