JavaFX 2.0布局窗格– GridPane

毫无疑问, GridPane是JavaFX 2.0中功能最强大,最灵活的布局窗格。
它在由行和列组成的灵活网格中布置其子项,与Swing的GridBagLayout或HTML的表格模型非常相似。 这种方法使该窗格非常适合于任何形式的表单(例如网站上的联系表单)。

您有能力...

  • 将任何Node应用于GridPane的单元格(由列和行指定)
  • Node跨越多个列/行
  • 使Node在其所应用于的单元格中对齐
  • Node设置水平或垂直增长
  • 并保留要保留在单元中Node周围的边距。
JavaFX 2.0布局窗格– GridPane

GridPane的灵活性也扩展到了非常灵活的API。 您可以使用诸如setColumnIndex(node, index)setRowSpan(node, value)类的静态类方法,也可以使用诸如gridpane.add(node, column, row, columnSpan, rowSpan)类的便捷实例方法。

注意:

  • GridPane的最大列数或行数,因为它会自动增长。
  • 一列的大小由该列中最宽的Node自动确定,每行的高度由该行中的最高Node确定。

最后一点可能是有关GridPane的最重要的事实,因为必须考虑每个单个Node的列/行和列跨度/行跨度,才能获得所需的布局。
对于更复杂的布局,最好在一张纸上绘制布局,并为列和行绘制所有线条。 这将简化开发,因为您可以直接查看每个Node必须放置在哪个单元格中以及它们必须跨越多少行或列。

让我们看一下第一个简单的例子:

GridPane –示例1

import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

/**
 * Created on: 23.06.2012
 * @author Sebastian Damm
 */
public class GridPaneExample extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        GridPane gridPane = new GridPane();
        gridPane.setPadding(new Insets(40, 0, 0, 50));
        gridPane.setHgap(5); gridPane.setVgap(5);
        
        Scene scene = new Scene(gridPane, 300, 150);
        
        Label lbUser = new Label('Username:');
        GridPane.setHalignment(lbUser, HPos.RIGHT);
        TextField tfUser = new TextField();
        
        Label lbPass = new Label('Password:');
        GridPane.setHalignment(lbPass, HPos.RIGHT);
        PasswordField tfPass = new PasswordField();
        
        Button btLogin = new Button('Login');
        GridPane.setMargin(btLogin, new Insets(10, 0, 0, 0));

        gridPane.add(lbUser, 0, 0);
        gridPane.add(tfUser, 1, 0);
        gridPane.add(lbPass, 0, 1);
        gridPane.add(tfPass, 1, 1);
        gridPane.add(btLogin, 1, 2);
        
        primaryStage.setTitle('GridPaneExample 1');
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args)
    {   Application.launch(args);   }
}

在这里,您可以看到一个小的登录表单,其中包含两个标签和两个用于用户名和密码的文本字段。 此外,还有一个“登录”按钮。
在第21-23行中,我们创建GridPane并应用一些填充。 此外,您可以指定每个Node之间要保留的水平和垂直间隙。 接下来,看一下第28行:可以使用静态类方法GridPane.setHalignment(Node node, HPos pos)分别设置GridPane.setValignment(Node node, VPos pos) GridPane.setHalignment(Node node, HPos pos)来设置Node在其放入的单元格边界内的对齐方式。 GridPane.setValignment(Node node, VPos pos)
在第36行中,您可以看到如何通过使用GridPane.setMargin(Node node, Insets insets)方法在单个Node周围放置单个边距。
最后,在线路38至42,我们每个添加NodeGridPane并指定列和排Node

您的应用程序现在应如下所示:

JavaFX 2.0布局窗格– GridPane

在下一个示例中,您将看到为什么我们需要在更复杂的布局中设置每个Node的列跨度和行跨度。 看一下这段代码:

GridPane –示例2:用户表单

import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradientBuilder;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;

/**
 * Created on: 23.06.2012
 * @author Sebastian Damm
 */
public class GridPaneExample2 extends Application
{
    private final Paint background = RadialGradientBuilder.create()
            .stops(new Stop(0d, Color.TURQUOISE), new Stop(1, Color.web('3A5998')))
            .centerX(0.5d).centerY(0.5d).build();
    private final String LABEL_STYLE = '-fx-text-fill: white; -fx-font-size: 14;'
            + '-fx-effect: dropshadow(one-pass-box, black, 5, 0, 1, 1);';
    
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Scene scene = new Scene(createGridPane(), 370, 250, background);
        primaryStage.setTitle('GridPaneExample 2 - User form');
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private GridPane createGridPane()
    {
        GridPane gridPane = new GridPane();
        gridPane.setPadding(new Insets(20, 0, 20, 20));
        gridPane.setHgap(7); gridPane.setVgap(7);
        
        Label lbFirstName = new Label('First Name:');
        lbFirstName.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbFirstName, HPos.RIGHT);
        TextField tfFirstName = new TextField();
        
        Label lbLastName = new Label('Last Name:');
        lbLastName.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbLastName, HPos.RIGHT);
        TextField tfLastName = new TextField();
        
        Label lbCity = new Label('City:');
        lbCity.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbCity, HPos.RIGHT);
        TextField tfCity = new TextField();
        
        Label lbStreetNr = new Label('Street/Nr.:');
        lbStreetNr.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbStreetNr, HPos.RIGHT);
        TextField tfStreet = new TextField();
        tfStreet.setPrefColumnCount(14);
        GridPane.setColumnSpan(tfStreet, 2);
        TextField tfNumber = new TextField();
        tfNumber.setPrefColumnCount(3);
        
        Label lbNotes = new Label('Notes:');
        lbNotes.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbNotes, HPos.RIGHT);
        TextArea taNotes = new TextArea();
        taNotes.setPrefColumnCount(5);
        taNotes.setPrefRowCount(5);
        GridPane.setColumnSpan(taNotes, 3);
        GridPane.setRowSpan(taNotes, 2);    
        
        ImageView imageView = new ImageView(new Image(getClass()
                .getResourceAsStream('person.png'), 0, 65, true, true));
        GridPane.setHalignment(imageView, HPos.LEFT);
        GridPane.setColumnSpan(imageView, 2);
        GridPane.setRowSpan(imageView, 3);
        
//        gridPane.setGridLinesVisible(true);
        
        gridPane.add(lbFirstName, 0, 0); gridPane.add(tfFirstName, 1, 0);
        gridPane.add(imageView, 2, 0); gridPane.add(lbLastName, 0, 1);
        gridPane.add(tfLastName, 1, 1); gridPane.add(lbCity, 0, 2);
        gridPane.add(tfCity, 1, 2); gridPane.add(lbStreetNr, 0, 3);
        gridPane.add(tfStreet, 1, 3); gridPane.add(tfNumber, 3, 3);
        gridPane.add(lbNotes, 0, 4); gridPane.add(taNotes, 1, 4);
        
        return gridPane;
    }
    
    public static void main(String[] args)
    {   Application.launch(args);   }
}

在此示例中,我们创建具有不同输入和图像的用户表单。 为了使应用程序看起来更好,我为Scene的背景创建了RadialGradient ,并为每个标签应用了白色字体颜色和一些阴影。

该应用程序应如下所示:

JavaFX 2.0布局窗格– GridPane

与前面的示例相比,第一个差异发生在第64行。
使用GridPane.setColumnSpan(tfStreet, 2); 我告诉这个TextField占据两列。 这是必需的,因为我希望此文本字段比其他文本字段宽一点(请参见第63行)。 否则,第二列将与该文本字段一样宽,因此将较小的文本字段拉伸。
TextArea (从第71行开始)和ImageView (从77行开始)跨越多个列和行。
接下来,看一下第83行。如果删除注释行并启动应用程序,则它应如下所示:

JavaFX 2.0布局窗格– GridPane

如您所见,此方法使所有网格线(包括每个Node之间的水平和垂直间隙)可见,如果您的Nodes没有按照您希望的方式对齐,这将是一个很大的帮助。
我不知道在学习Swing和GridBagLayout过程中我希望有多少次这样的方法,我敢打赌我不是唯一的一个;)

最后,请删除所有指定了列跨度或行跨度的行(第64、74、75、80、81行)。 这将帮助您了解列跨度和行跨度的必要性。

JavaFX 2.0布局窗格– GridPane
JavaFX 2.0布局窗格– GridPane

您会看到,每个Node占用一个单元格,并且布局非常混乱,因为每列/行的宽度/高度取决于最宽/最高的子Node

GridPane –示例3:setConstraints方法

实例方法add '提供了两种版本,一种具有Node ,列和行,一种具有附加的列跨度和行跨度。 如前两个示例中一样,必须使用专用的类方法(例如GridPane.setHalignment来设置其他属性(如对齐或增长)。

但是还有另一种不错的方法: GridPane.setConstraints(...)方法。 目前(JavaFX 2.2) setConstraints(Node child, int columnIndex, int rowIndex)有五个此方法的重载版本setConstraints(Node child, int columnIndex, int rowIndex)

设置setConstraints(Node child, int columnIndex, int rowIndex, int columnspan, int rowspan, HPos halignment, VPos valignment, Priority hgrow, Priority vgrow, Insets margin)

这与Swing的GridBagConstraints非常相似,但是在这里您不必创建专用对象并将其重用于多个图形对象。

如果将约束应用于这样的每个Node ,则只需将Nodes添加到GridPane´s的子GridPane´s集合中即可。

使用这种方法,第二个示例的代码如下所示:

  
    private GridPane createGrid()
    {
        GridPane gridPane = new GridPane();
        gridPane.setPadding(new Insets(20, 0, 20, 20));
        gridPane.setHgap(7); gridPane.setVgap(7);
        
        Label lbFirstName = new Label('First Name:');
        lbFirstName.setStyle(LABEL_STYLE);
        GridPane.setConstraints(lbFirstName, 0, 0, 1, 1, HPos.RIGHT, VPos.CENTER);
        TextField tfFirstName = new TextField();
        GridPane.setConstraints(tfFirstName, 1, 0);
        
        Label lbLastName = new Label('Last Name:');
        lbLastName.setStyle(LABEL_STYLE);
        GridPane.setConstraints(lbLastName, 0, 1, 1, 1, HPos.RIGHT, VPos.CENTER);
        TextField tfLastName = new TextField();
        GridPane.setConstraints(tfLastName, 1, 1);
        
        Label lbCity = new Label('City:');
        lbCity.setStyle(LABEL_STYLE);
        GridPane.setConstraints(lbCity, 0, 2, 1, 1, HPos.RIGHT, VPos.CENTER);
        
        TextField tfCity = new TextField();
        GridPane.setConstraints(tfCity, 1, 2);
        
        Label lbStreetNr = new Label('Street/Nr.:');
        lbStreetNr.setStyle(LABEL_STYLE);
        GridPane.setConstraints(lbStreetNr, 0, 3, 1, 1, HPos.RIGHT, VPos.CENTER);
        
        TextField tfStreet = new TextField();
        tfStreet.setPrefColumnCount(14);
        GridPane.setConstraints(tfStreet, 1, 3, 2, 1);
        
        TextField tfNumber = new TextField();
        tfNumber.setPrefColumnCount(3);
        GridPane.setConstraints(tfNumber, 3, 3);
        
        Label lbNotes = new Label('Notes:');
        lbNotes.setStyle(LABEL_STYLE);
        GridPane.setConstraints(lbNotes, 0, 4, 1, 1, HPos.RIGHT, VPos.CENTER);
        
        TextArea taNotes = new TextArea();
        taNotes.setPrefColumnCount(5);
        taNotes.setPrefRowCount(5);
        GridPane.setConstraints(taNotes, 1, 4, 3, 2);
                
        ImageView imageView = new ImageView(new Image(getClass()
                .getResourceAsStream('person.png'), 0, 65, true, true));
        GridPane.setConstraints(imageView, 2, 0, 3, 3, HPos.LEFT, VPos.CENTER);
        
        gridPane.getChildren().addAll(lbFirstName, tfFirstName, imageView
                , lbLastName, tfLastName, lbCity, tfCity, lbStreetNr, tfStreet
                , tfNumber, lbNotes, taNotes);
        return gridPane;
    }

您可以在第51-53行看到重载的setConstraints(...)方法的用法,以及如何将Nodes简单地添加到GridPane

我希望我能对JavaFX 2.0中的GridPane进行很好的介绍。 随时添加评论和发表问题。

参考: JavaFX 2.0布局窗格–来自我们JCG合作伙伴 Sebastian Damm的GridPane ,在Java博客上的Just my 2 cents上。

翻译自: https://www.javacodegeeks.com/2012/07/javafx-20-layout-panes-gridpane.html