JavaFX 2.0 Layout Panes – GridPane

The GridPane is without a doubt the most powerfull and flexible layout pane in JavaFX 2.0.
It lays out its children in a flexible grid of columns and rows and is very similar to Swing´s GridBagLayout or HTML´s table model. This approach makes this pane very well suited for any kind of form (like contact forms on a website).

You have the ability to…

  • apply any Node to a cell (specified by column and row) in the GridPane
  • to let the Node span multiple columns/rows
  • to align the Node in the cell it was applied to
  • to set horizontal or vertical grow for the Node
  • and to apply a margin to be kept around the Node in the cell.

The flexibility of the GridPane also extends to a very flexible API. You can use static class methods like setColumnIndex(node, index) or setRowSpan(node, value), or you can use convenience instance methods like gridpane.add(node, column, row, columnSpan, rowSpan).

Note:

  • You don´t have to set the maximum number of columns or rows in the GridPane as it will grow automatically.
  • The size of one column is automatically determined by the widest Node in this column, the height of each row is determined by the tallest Node in the row.

The last note is probably the most important fact about the GridPane as it has to be considered for the column/row and the column span/row span of every single Node in order to get the layout you want.
For more complex layouts it is a very good idea to draw the layout on a piece of paper and to draw all lines for the columns and rows. This will ease development because you can diretly see in which cell you have to put each Node and how many rows or columns they have to span.

Lets have a look at the first simple example:

GridPane – Example 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);   }
}

Here you can see a little login form with with two labels and two textfields for the username and the password. Additionally theres a ‘login’ button.
In lines 21-23 we create the GridPane and apply some padding. Furthermore you can specify a horizontal and a vertical gap to be kept between each Node. Next, take a look at line 28: The alignment of a Node inside the boundaries of the cell it was put into, can be set with the static class methods GridPane.setHalignment(Node node, HPos pos), respectively GridPane.setValignment(Node node, VPos pos).
In line 36 you can see how to put a individual margin around a single Node by using the GridPane.setMargin(Node node, Insets insets) method.
Finally in lines 38 to 42 we add each Node to the GridPane and specify the column and the row of the Node.

Your application should look like this now:

In the next example you will see, why we need to set the column span and the row span of each Node in more complex layouts. Have a look at this code:

GridPane – Example 2: User form

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

In this example we create a user form with different inputs and an image. To make the application appear a little nicer, i created a RadialGradient for the background of the Scene and applied a white font color and a little dropshadow to each label.

The application should look like this:

Compared to the previous example, the first difference occurs in line 64.
With GridPane.setColumnSpan(tfStreet, 2); i tell this TextField to occupy two columns. This is needed, because i want this textfield to be a little wider (see line 63) than the other textfields. Otherwise the second column would be as wide as this textfield and therefore stretch the smaller ones.
The TextArea (starting at line 71) and the ImageView (line 77) span across multiple columns and rows.
Next, take a look at line 83. If you remove the comment lines and start the application, it should look like this:

As you can see, this method makes all grid lines (including the horizontal and vertical gap between each Node visible which can be a great help if your Nodes arent aligned the way you want it.
I don´t know how many times i wished for a method like this during the time i learned Swing and the GridBagLayout and i bet that i´m not the only one ;)

Finally, please remove all lines, where column span or row span are specified (lines 64, 74, 75, 80, 81). This will help you to understand the necessity of column span and row span.

You can see, that each Node occupies one single cell and that the layout is pretty messed up because the width/height of each column/row depend on the widest/tallest child Node.

GridPane – Example 3: The setConstraints method

The instance method add ‘only’ provides two versions, one with the Node, the column and the row, and one with additional column span and row span. Other properties like the alignment or the grow have to be set with dedicated class methods like GridPane.setHalignment like in the first two examples.

But theres another nice way: the GridPane.setConstraints(...)method. At the moment (JavaFX 2.2) there are five overloaded versions of this method from setConstraints(Node child, int columnIndex, int rowIndex)

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

This is pretty similiar to Swing´s GridBagConstraints but here you don´t have to create a dedicated object and reuse it for multiple graphical objects.

If you apply the constraints to every Node like this, you can simply add the Nodes to the GridPane´s collections of children.

With this approach the code of the second example looks like this:

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

You can see the usage of the overloaded setConstraints(...) methods and how you can simply add the Nodes to the GridPane in lines 51-53.

I hope i could provide a good introduction to the GridPane in JavaFX 2.0. Feel free to add comments and post questions.

Reference: JavaFX 2.0 Layout Panes – GridPane from our JCG partner Sebastian Damm at the Just my 2 cents about Java blog.

Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

One Response to "JavaFX 2.0 Layout Panes – GridPane"

  1. nandish says:

    superb tutorial thanks a lot.

Leave a Reply


nine − 1 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books