Current Tutorial
JavaFX Layout Controls

JavaFX Layout Controls

This page was contributed by Gail C. Anderson and Paul Anderson under the UPL and is from The Definitive Guide to Modern Java Clients with JavaFX 17 graciously contributed by Apress.

 

Introduction

To manage the nodes of a scene, you use one or more of these controls. Each control is designed for a particular layout configuration. Furthermore, you can nest layout controls to manage groups of nodes and specify how the layout should react to events, such as resizing or changes to the managed nodes. You can specify alignment settings as well as margin controls and padding.

There are several ways to add nodes to layout containers. You can add child nodes with the layout container’s constructor. You can also use method getChildren().add() for a single node and method getChildren().addAll() for multiple nodes. In addition, some layout controls have specialized methods for adding nodes. Let’s look at a few commonly used layout controls now to show you how JavaFX can compose a scene for you.  

StackPane

A convenient and easy layout container is StackPane. This layout control stacks its children from back to front in the order that you add nodes. Note that we add the ellipse first so that it appears behind the text node. In the opposite order, the ellipse would obscure the text element.

By default, StackPane centers all of its children. You can provide a different alignment for the children or apply an alignment to a specific node in the StackPane. For example,

// align the text only
stackPane.setAlignment(text, Pos.BOTTOM_CENTER);

centers the text node along the bottom edge of the StackPane. Now when you resize the window, the ellipse remains centered, and the text remains anchored to the bottom edge of the window. To specify the alignment of all managed nodes to the bottom edge, use

// align all managed nodes
stackPane.setAlignment(Pos.BOTTOM_CENTER);

Although both the ellipse and the text appear at the bottom of the window, they won’t be centered relative to each other. Why not?  

AnchorPane

AnchorPane manages its children according to configured anchor points, even when a container resizes. You specify an offset from the pane’s edge for a component. Here, we add a Label to an AnchorPane and anchor it to the lower-left side of the pane with a 10-pixel offset:

AnchorPane anchorPane = new AnchorPane();
Label label = new Label("My Label");
anchorPane.getChildren().add(label);
AnchorPane.setLeftAnchor(label, 10.0);
AnchorPane.setBottomAnchor(label, 10.0);

AnchorPane is typically used as a top-level layout manager for controlling margins, even when the window is resized.  

GridPane

GridPane lets you place child nodes in a flexibly sized two-dimensional grid. Components can span rows and/or columns, but the row size is consistent for all components in a given row. Similarly, the column’s width is consistent for a given column. GridPane has specialized methods that add nodes to a particular cell designated by a column and row number. Optional arguments let you specify column and row span values. For example, the first label here is placed in the cell corresponding to column 0 and row 0. The second label goes into the cell corresponding to column 1 and row 0, and it spans two columns (the second and third columns). We must also provide a row span value (here it is set to 1):

GridPane gridPane = new GridPane();
gridPane.add(new Label("Label1"), 0, 0);
gridPane.add(new Label("Label2 is very long"), 1, 0, 2, 1);

GridPane is useful for laying out components in forms that accommodate columns or rows of various sizes. GridPane also allows nodes to span either multiple columns or rows. We use GridPane in our master-detail UI example (see Putting It All Together section of this series).  

FlowPane and TilePane

FlowPane manages its children in either a horizontal or vertical flow. The default orientation is horizontal. You can specify the flow direction with the constructor or use method setOrientation(). Here, we specify a vertical orientation with the constructor:

FlowPane flowpane = new FlowPane(Orientation.VERTICAL);

FlowPane wraps child nodes according to a configurable boundary. If you resize a pane that contains a FlowPane, the layout will adjust the flow as needed. The size of the cells depends on the size of the nodes, and it will not be a uniform grid unless all the nodes are the same size. This layout is convenient for nodes whose sizes can vary, such as ImageView nodes or shapes. TilePane is similar to FlowPane, except TilePane uses equal-sized cells.  

BorderPane

BorderPane is convenient for desktop applications with discreet sections, including a top toolbar (Top), a bottom status bar (Bottom), a center work area (Center), and two side areas (Right and Left). Any of the five sections can be empty. Here is an example of a BorderPane with a rectangle in the center and a label at the top:

BorderPane borderPane = new BorderPane();
Label colorLabel = new Label("Color: Lightblue");
colorLabel.setFont(new Font("Verdana", 18));
borderPane.setTop(colorLabel);
Rectangle rectangle = new Rectangle(100, 50, Color.LIGHTBLUE);
borderPane.setCenter(rectangle);
BorderPane.setAlignment(colorLabel, Pos.CENTER);
BorderPane.setMargin(colorLabel, new Insets(20,10,5,10));

Note that BorderPane uses a center alignment by default for the center area and a left alignment for the top. To keep the top area label centered, we configure its alignment with Pos.CENTER. We also set margins around the label with BorderPane static method setMargin(). The Insets constructor takes four values corresponding to the top, right, bottom, and left edges. Similar alignment and margin configurations apply to other layout components, too.  

SplitPane

SplitPane divides the layout space into multiple horizontally or vertically configured areas. The divider is movable, and you typically use other layout controls in each of SplitPane’s areas. We use SplitPane in our master-detail UI example (checkout Putting It All Together part of these series).  

HBox, VBox, and ButtonBar

The HBox and VBox layout controls provide single horizontal or vertical placements for child nodes. You can nest HBox nodes inside a VBox for a grid-like effect or nest VBox nodes inside an HBox component. ButtonBar is convenient for placing a row of buttons of equal size in a horizontal container.  

Make a Scene

Returning to MyShapes, the Scene holds the scene graph, defined by its root node.

package org.modernclient;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MyShapes extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        // Create an Ellipse and set fill color
        Ellipse ellipse = new Ellipse(110, 70);
        ellipse.setFill(Color.LIGHTBLUE);
        // Create a Text shape with font and size
        Text text = new Text("My Shapes");
        text.setFont(new Font("Arial Bold", 24));
        StackPane stackPane = new StackPane();
        stackPane.getChildren().addAll(ellipse, text);
        Scene scene = new Scene(stackPane, 350, 230,
                       Color.LIGHTYELLOW);
        stage.setTitle("MyShapes with JavaFX");
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

First, we construct the Scene and provide stackPane as the root node. We then specify its width and height in pixels and supply an optional fill argument for the background (Color.LIGHTYELLOW). What’s left is to configure the Stage. We provide a title, set the scene, and show the stage. The JavaFX runtime renders our scene. Below is a hierarchical view of the scene graph for our MyShapes application. The root node is the StackPane, which contains its two child nodes, Ellipse and Text.

MyShapes scene graph


Last update: September 12, 2023


Current Tutorial
JavaFX Layout Controls