JavaFx GridPane 中的相对大小

Posted

技术标签:

【中文标题】JavaFx GridPane 中的相对大小【英文标题】:Relative sizing in JavaFx GridPane 【发布时间】:2020-12-05 04:19:30 【问题描述】:

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

例如,如果我想要五行,其中三行是未知的固定大小,一排占用剩余空间的三分之一,另一排占用剩余空间的三分之二(见下图),我该如何实现?

我查看了使用RowConstraints,其中两个有row.setVgrow(Priority.ALWAYS);,但这仅允许平均共享剩余空间。

我尝试使用百分比,正如我在文档 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);
    

【问题讨论】:

没有尝试 - 但会遵循您的假设。您可以尝试一个自定义布局,它与 gridPane(扩展或 c&p)大部分相同,但顺序相反:将相对大小的空间计算移动到末尾。 @kleopatra 感谢您的建议。将调查:) 【参考方案1】:

如果您能够使用 3rd 方库,就我而言,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>

【讨论】:

【参考方案2】:

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

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

这里是例子:

当第一行和最后一行应该有固定的高度值时,您可以使用BorderPane 作为根。对于中心,您可以拥有一个GridPane,其中两行具有基于百分比的值。然后它的第二行可以包含 e。 G。 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>

【讨论】:

感谢您的回答。我可能会尝试修改布局 从头开始,我刚刚发现 JavaFX 支持 MigLayout,哈哈。我将使用它,但感谢您的帮助

以上是关于JavaFx GridPane 中的相对大小的主要内容,如果未能解决你的问题,请参考以下文章

Javafx:GridPane:当文本太长时防止列增加宽度

Javafx 中 GridPane 中的 HBox

JavaFX:通过窗口大小调整来调整GridPane的大小

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

可以决定 GridPane (JavaFX) 中的行数和列数

子节点的 JavaFX GridPane 动态调整大小以填充分配的区域