JavaFx GridPane 中的相对大小

Relative sizing in JavaFx GridPane

如何使用 GridPane 上的权重设置行/列大小?

例如,如果我想要五行,其中三行是未知的固定大小,一个占剩余 space 的三分之一,另一个占剩余 space 的三分之二(见图下面),我怎样才能做到这一点?

我考虑使用 RowConstraints,其中两个 row.setVgrow(Priority.ALWAYS); 但这只允许平分剩余的 space。

我尝试使用百分比,正如我在文档中看到的那样 that if the sum of the widthPercent (or heightPercent) values total greater than 100, the values will be treated as weights. e.g. if 3 columns are each given a widthPercent of 50, then each will be allocated 1/3 of the gridpane's available width (50/(50+50+50)).

问题是,当我尝试这样做时,我丢失了部分应用程序

我想这也是文档中说 An application may freely mix the size-types of rows/columns (computed from content, fixed, or percentage). The percentage rows/columns will always be allocated space first based on their percentage of the gridpane's available space (size minus insets and gaps). The remaining space will be allocated to rows/columns given their minimum, preferred, and maximum sizes and grow priorities.

的部分原因

JavaFx MCVE

package sample;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        GridPane root = new GridPane();
        root.setGridLinesVisible(true);

        ColumnConstraints columnOneConstraints = new ColumnConstraints();
        columnOneConstraints.setHgrow(Priority.ALWAYS);
        root.getColumnConstraints().addAll(columnOneConstraints);

        RowConstraints rowOneConstraints = new RowConstraints();
        RowConstraints rowTwoConstraints = new RowConstraints();
        rowTwoConstraints.setVgrow(Priority.ALWAYS);
        rowTwoConstraints.setPercentHeight(2000);
        RowConstraints rowThreeConstraints = new RowConstraints();
        RowConstraints rowFourConstraints = new RowConstraints();
        rowFourConstraints.setVgrow(Priority.ALWAYS);
        rowFourConstraints.setPercentHeight(1000);
        RowConstraints rowFiveConstraints = new RowConstraints();
        root.getRowConstraints().addAll(
                rowOneConstraints,
                rowTwoConstraints,
                rowThreeConstraints,
                rowFourConstraints,
                rowFiveConstraints
        );

        Background red = new Background(new BackgroundFill(Color.RED, null, null));
        Background blue = new Background(new BackgroundFill(Color.BLUE, null, null));

        Label rowOne = new Label("R1: Unknown Fixed Size");
        rowOne.backgroundProperty().set(red);
        rowOne.setMaxWidth(Double.MAX_VALUE);
        rowOne.setAlignment(Pos.CENTER);
        rowOne.setTextFill(Color.WHITE);
        rowOne.setMaxHeight(Double.MAX_VALUE);
        root.add(rowOne, 0, 0, 1, 1);

        Label rowTwo = new Label("R2: Grow 2 parts of the remaining space");
        rowTwo.backgroundProperty().set(blue);
        rowTwo.setTextFill(Color.WHITE);
        rowTwo.setAlignment(Pos.CENTER);
        rowTwo.setMaxWidth(Double.MAX_VALUE);
        rowTwo.setMaxHeight(Double.MAX_VALUE);
        root.add(rowTwo, 0, 1, 1, 1);

        Label rowThree = new Label("R3: Unknown Fixed Size");
        rowThree.backgroundProperty().set(red);
        rowThree.setTextFill(Color.WHITE);
        rowThree.setAlignment(Pos.CENTER);
        rowThree.setMaxWidth(Double.MAX_VALUE);
        rowThree.setMaxHeight(Double.MAX_VALUE);
        root.add(rowThree, 0, 2, 1, 1);

        Label rowFour = new Label("R4: Grow 1 part of the remaining space");
        rowFour.backgroundProperty().set(blue);
        rowFour.setTextFill(Color.WHITE);
        rowFour.setAlignment(Pos.CENTER);
        rowFour.setMaxWidth(Double.MAX_VALUE);
        rowFour.setMaxHeight(Double.MAX_VALUE);
        root.add(rowFour, 0, 3, 1, 1);

        Label rowFive = new Label("R5: Unknown Fixed Size");
        rowFive.backgroundProperty().set(red);
        rowFive.setTextFill(Color.WHITE);
        rowFive.setAlignment(Pos.CENTER);
        rowFive.setMaxWidth(Double.MAX_VALUE);
        rowFive.setMaxHeight(Double.MAX_VALUE);
        root.add(rowFive, 0, 4, 1, 1);

        primaryStage.setScene(new Scene(root));
        primaryStage.sizeToScene();
        primaryStage.show();
        primaryStage.setMinHeight(primaryStage.getHeight());
        primaryStage.setMinWidth(primaryStage.getWidth());
    }
}

我想要的可以用 Swing 的 GridBagLayout 生成,但显然这不能用于 GridPane

package sample;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel(new GridBagLayout());

        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.weightx = 1;

        JLabel rowOne = new JLabel("R1: Unknown Fixed Size", SwingConstants.CENTER);
        rowOne.setBackground(Color.RED);
        rowOne.setForeground(Color.WHITE);
        rowOne.setOpaque(true);
        constraints.gridy = 0;
        constraints.weighty = 0;
        panel.add(rowOne, constraints);

        JLabel rowTwo = new JLabel("R2: Grow 2 parts of remaining space", SwingConstants.CENTER);
        rowTwo.setBackground(Color.BLUE);
        rowTwo.setForeground(Color.WHITE);
        rowTwo.setOpaque(true);
        constraints.gridy = 1;
        constraints.weighty = 2;
        panel.add(rowTwo, constraints);

        JLabel rowThree = new JLabel("R3: Unknown Fixed Size", SwingConstants.CENTER);
        rowThree.setBackground(Color.RED);
        rowThree.setForeground(Color.WHITE);
        rowThree.setOpaque(true);
        constraints.gridy = 2;
        constraints.weighty = 0;
        panel.add(rowThree, constraints);

        JLabel rowFour = new JLabel("R4: Grow 1 part of the remaining space", SwingConstants.CENTER);
        rowFour.setBackground(Color.BLUE);
        rowFour.setForeground(Color.WHITE);
        rowFour.setOpaque(true);
        constraints.gridy = 3;
        constraints.weighty = 1;
        panel.add(rowFour, constraints);

        JLabel rowFive = new JLabel("R5: Unknown Fixed Size", SwingConstants.CENTER);
        rowFive.setBackground(Color.RED);
        rowFive.setForeground(Color.WHITE);
        rowFive.setOpaque(true);
        constraints.gridy = 4;
        constraints.weighty = 0;
        panel.add(rowFive, constraints);

        frame.getContentPane().add(panel);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setMinimumSize(frame.getSize());
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

据我所知,仅使用默认的 JavaFX GridPane 无法实现您的示例显示的内容。本论坛专业人士的标准答案是:创建您自己的自定义(类似 GridBag 的)布局。 ;-P

如果您想使用 JavaFX 提供的默认选项,您可以使用 e 的组合。 G。 BorderPaneGridPane。这与您的示例所显示的不完全相同,但也许接近它。您需要决定它是否足以满足您的需求。

举个例子:

当第一行和最后一行应该有固定的高度值时,您可以使用 BorderPane 作为根。对于中心,您可以有一个 GridPane 和两行,这些行具有基于百分比的值。然后它的第二行可以包含 e。 G。 a BorderPane(顶部节点的固定高度)等等。

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?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?>

<BorderPane prefHeight="600.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
   <top>
      <HBox alignment="CENTER" style="-fx-background-color: lightgreen;" BorderPane.alignment="CENTER">
         <children>
            <Label text="&quot;R1&quot;" />
         </children>
      </HBox>
   </top>
   <bottom>
      <HBox alignment="CENTER" style="-fx-background-color: lightgreen;" BorderPane.alignment="CENTER">
         <children>
            <Label text="&quot;R5&quot;" />
         </children>
      </HBox>
   </bottom>
   <center>
      <GridPane BorderPane.alignment="CENTER">
        <columnConstraints>
          <ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints percentHeight="60.0" vgrow="SOMETIMES" />
          <RowConstraints percentHeight="40.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <HBox alignment="CENTER" style="-fx-background-color: tomato;">
               <children>
                  <Label text="&quot;R2&quot;" />
               </children>
            </HBox>
            <BorderPane GridPane.rowIndex="1">
               <center>
                  <HBox alignment="CENTER" style="-fx-background-color: tomato;">
                     <children>
                        <Label text="&quot;R4&quot;" />
                     </children>
                  </HBox>
               </center>
               <top>
                  <HBox alignment="CENTER" style="-fx-background-color: lightgreen;" BorderPane.alignment="CENTER">
                     <children>
                        <Label text="&quot;R3&quot;" />
                     </children>
                  </HBox>
               </top>
            </BorderPane>
         </children>
      </GridPane>
   </center>
</BorderPane>

如果您能够使用第 3 方库,就我而言,MigLayout 是一个不错的选择。

实现我想要的布局变得简单,它还支持 FXML。

package sample;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import org.tbee.javafx.scene.layout.MigPane;

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        MigPane root = new MigPane(
                "fill, debug, wrap, gap 0, insets 0",
                "[fill, grow]",
                "[fill][fill, grow 2][fill][fill, grow 1][fill]"
        );

        Background red = new Background(new BackgroundFill(Color.RED, null, null));
        Background blue = new Background(new BackgroundFill(Color.BLUE, null, null));

        Label rowOne = new Label("R1: Unknown Fixed Size");
        rowOne.backgroundProperty().set(red);
        rowOne.setAlignment(Pos.CENTER);
        rowOne.setTextFill(Color.WHITE);
        root.add(rowOne);

        Label rowTwo = new Label("R2: Grow 2 parts of the remaining space");
        rowTwo.backgroundProperty().set(blue);
        rowTwo.setTextFill(Color.WHITE);
        rowTwo.setAlignment(Pos.CENTER);
        root.add(rowTwo);

        Label rowThree = new Label("R3: Unknown Fixed Size");
        rowThree.backgroundProperty().set(red);
        rowThree.setTextFill(Color.WHITE);
        rowThree.setAlignment(Pos.CENTER);
        root.add(rowThree);

        Label rowFour = new Label("R4: Grow 1 part of the remaining space");
        rowFour.backgroundProperty().set(blue);
        rowFour.setTextFill(Color.WHITE);
        rowFour.setAlignment(Pos.CENTER);
        root.add(rowFour);

        Label rowFive = new Label("R5: Unknown Fixed Size");
        rowFive.backgroundProperty().set(red);
        rowFive.setTextFill(Color.WHITE);
        rowFive.setAlignment(Pos.CENTER);
        root.add(rowFive);

        primaryStage.setScene(new Scene(root));
        primaryStage.sizeToScene();
        primaryStage.show();
        primaryStage.setMinHeight(primaryStage.getHeight());
        primaryStage.setMinWidth(primaryStage.getWidth());
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import org.tbee.javafx.scene.layout.fxml.MigPane?>

<MigPane layout="fill, gap 10 10, debug, wrap"
         cols="fill, grow"
         rows="[][grow 2][][grow 1][]">

    <Label text="Row One"
           alignment="CENTER" />

    <Label text="Row Two"
           alignment="CENTER" />

    <Label text="Row Three"
           alignment="CENTER" />

    <Label text="Row Four"
           alignment="CENTER" />

    <Label text="Row Five"
           alignment="CENTER" />
</MigPane>