Layout Panes
Tags: java, programming, learning, beginners
Published: 2024-06-20 18:01:33

JavaFX provides many types of panes for automatically laying out nodes in a desired location and size. JavaFX provides many types of panes for organizing nodes in a container, as shown in Table below. You have used the layout panes **Pane**, **StackPane**, and **HBox** in the preceding sections for containing nodes. This section introduces the panes in more details.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvzt0fpsk2xnfzftyf8b.png)

You have used the **Pane** in [here](https://dev.to/paulike/panes-ui-controls-and-shapes-hb6), ShowCircle.java. A **Pane** is usually used as a canvas for displaying shapes. **Pane** is the base class for all specialized panes. You have used a specialized pane **StackPane** in [here](https://dev.to/paulike/panes-ui-controls-and-shapes-hb6), ButtonInPane.java. Nodes are placed in the center of a **StackPane**. Each pane contains a list for holding nodes in the pane. This list is an instance of **ObservableList**, which can be obtained using pane’s **getChildren()** method. You can use the **add(node)** method to add an element to the list, use **addAll(node1, node2, ...)** to add a variable number of nodes to the pane.

## FlowPane

**FlowPane** arranges the nodes in the pane horizontally from left to right or vertically from top to bottom in the order in which they were added. When one row or one column is filled, a new row or column is started. You can specify the way the nodes are placed horizontally or vertically using one of two constants: **Orientation.HORIZONTAL** or **Orientation.VERTICAL**. You can also specify the gap between the nodes in pixels. The class diagram for **FlowPane** is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcgbx862vpt56zbaud1v.png)

Data fields **alignment**, **orientation**, **hgap**, and **vgap** are binding properties. Each binding property in JavaFX has a getter method (e.g., **getHgap()**) that returns its value, a setter method (e.g., **sethGap(double)**) for setting a value, and a getter method that returns the property itself (e.g., **hGapProperty()**). For a data field of **ObjectProperty<T>** type, the value getter method returns a value of type **T** and the property getter method returns a property value of type **ObjectProperty<T>**.

The program below gives a program that demonstrates **FlowPane**. The program adds labels and text fields to a **FlowPane**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cu3hkszomwneqxwwdzo.png)

The program creates a **FlowPane** (line 15) and sets its **padding** property with an **Insets** object (line 16). An **Insets** object specifies the size of the border of a pane. The constructor **Insets(11, 12, 13, 14)** creates an **Insets** with the border sizes for top (11), right (12), bottom (13), and left (14) in pixels, as shown in Figure below. You can also use the constructor **Insets(value)** to create an **Insets** with the same value for all four sides. The **hGap** and **vGap** properties are in lines 17–18 to specify the horizontal gap and vertical gap between two nodes in the pane, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8w1122q5tx74axq6qwmj.png)

Each **FlowPane** contains an object of **ObservableList** for holding the nodes. This list can be obtained using the **getChildren()** method (line 21). To add a node into a **FlowPane** is to add it to this list using the **add(node)** or **addAll(node1, node2, ...)** method. You can also remove a node from the list using the **remove(node)** method or use the **removeAll()** method to remove all nodes from the pane. The program adds the labels and text fields into the pane (lines 21–24). Invoking **tfMi.setPrefColumnCount(1)** sets the preferred column count to **1** for the MI text field (line 23). The program declares an explicit reference **tfMi** for a **TextField** object for MI. The explicit reference is necessary, because we need to reference the object directly to set its **prefColumnCount** property.

The program adds the pane to the scene (line 27), sets the scene in the stage (line 29), and displays the stage (line 30). Note that if you resize the window, the nodes are automatically rearranged to fit in the pane. In Figure below (a), the first row has three nodes, but in Figure below (b), the first row has four nodes, because the width has been increased.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrxwxp8fcf9ze5ovyvco.png)

Suppose you wish to add the object **tfMi** to a pane ten times; will ten text fields appear in the pane? No, a node such as a text field can be added to only one pane and once. Adding a node to a pane multiple times or to different panes will cause a runtime error. A node can be placed only in one pane. Therefore, the relationship between a pane and a node is the composition denoted by a filled diamond.

## GridPane

A **GridPane** arranges nodes in a grid (matrix) formation. The nodes are placed in the specified column and row indices. The class diagram for **GridPane** is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u2hwxoapsryucg8p85yo.png)

The program below gives a program that demonstrates **GridPane**, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0h38fde5uiczz8wfn2f.png)

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

public class ShowGridPane extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane and set its properties
		GridPane pane = new GridPane();
		pane.setAlignment(Pos.CENTER);
		pane.setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
		pane.setHgap(5.5);
		pane.setVgap(5.5);
		
		// Place nodes in the pane
		pane.add(new Label("First Name"), 0, 0);
		pane.add(new TextField(), 1, 0);
		pane.add(new Label("MI:"), 0, 1);
		pane.add(new TextField(), 1, 1);
		pane.add(new Label("Last Name"), 0, 2);
		pane.add(new TextField(), 1, 2);
		Button btAdd = new Button("Add Name");
		pane.add(btAdd, 1, 3);
		GridPane.setHalignment(btAdd, HPos.RIGHT);
	
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane);
		primaryStage.setTitle("ShowGridPane"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}
}

```

The program creates a **GridPane** (line 18) and sets its properties (line 19–22). The alignment is set to the center position (line 19), which causes the nodes to be placed in the center of the grid pane. If you resize the window, you will see the nodes remains in the center of the grid pane.

The program adds the label in column **0** and row **0** (line 25). The column and row index starts from **0**. The **add** method places a node in the specified column and row. Not every cell in the grid needs to be filled. A button is placed in column 1 and row 3 (line 32), but there are no nodes placed in column 0 and row 3. To remove a node from a **GridPane**, use **pane.getChildren().remove(node)**. To remove all nodes, use **pane.getChildren().removeAll()**.

The program invokes the static **setHalignment** method to align the button right in the cell (line 33).

Note that the scene size is not set (line 36). In this case, the scene size is automatically computed according to the sizes of the nodes placed inside the scene.

## BorderPane

A **BorderPane** can place nodes in five regions: top, bottom, left, right, and center, using the **setTop(node)**, **setBottom(node)**, **setLeft(node)**, **setRight(node)**, and **setCenter(node)** methods. The class diagram for **GridPane** is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ladeta3p1i81mrsjrber.png)

The program below gives a program that demonstrates **BorderPane**. The program places five buttons in the five regions of the pane, as shown in Figure below.

```
package application;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ShowBorderPane extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane and set its properties
		BorderPane pane = new BorderPane();
		
		// Place nodes in the pane
		pane.setTop(new CustomPane("Top"));
		pane.setRight(new CustomPane("Right"));
		pane.setBottom(new CustomPane("Buttom"));
		pane.setLeft(new CustomPane("Left"));
		pane.setCenter(new CustomPane("Center"));
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane);
		primaryStage.setTitle("ShowBorderPane"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}
}

// Define a custom pane to hold a label in the center of the pane
class CustomPane extends StackPane{
	public CustomPane(String title) {
		getChildren().add(new Label(title));
		setStyle("-fx-border-color: red");
		setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
	}
}

```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h5lws7epp1xeftmd0n5h.png)

The program defines **CustomPane** that extends **StackPane** (line 36). The constructor of **CustomPane** adds a label with the specified title (line 38), sets a style for the border color, and sets a padding using insets (line 40).

The program creates a **BorderPane** (line 14) and places five instances of **CustomPane** into five regions of the border pane (lines 17–21). Note that a pane is a node. So a pane can be added into another pane. To remove a node from the top region, invoke **setTop(null)**. If a region is not occupied, no space will be allocated for this region. 

## HBox and VBox

An **HBox** lays out its children in a single horizontal row. A **VBox** lays out its children in a single vertical column. Recall that a **FlowPane** can lay out its children in multiple rows or multiple columns, but an **HBox** or a **VBox** can lay out children only in one row or one column. The class diagrams for **HBox** and **VBox** are shown in Figures below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/znghk8gkb4wc1r0b941g.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pi2ati0lp2439oxb22uy.png)

The program below gives a program that demonstrates **HBox** and **VBox**. The program places two buttons in an **HBox** and five labels in a **VBox**, as shown in Figure below.

```
package application;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class ShowHBoxVBox extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane and set its properties
		BorderPane pane = new BorderPane();
		
		// Place nodes in the pane
		pane.setTop(getHBox());
		pane.setLeft(getVBox());
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane);
		primaryStage.setTitle("ShowHBoxVBox"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}
	
	private HBox getHBox() {
		HBox hBox = new HBox(15);
		hBox.setPadding(new Insets(15, 15, 15, 15));
		hBox.setStyle("-fx-background-color: gold");
		hBox.getChildren().add(new Button("Computer Science"));
		hBox.getChildren().add(new Button("Chemistry"));
		ImageView imageView = new ImageView(new Image("file:/C:/Users/Paul/development/MyJavaFX/src/application/image/ke.jpg"));
		hBox.getChildren().add(imageView);
		return hBox;
	}
	
	private VBox getVBox() {
		VBox vBox = new VBox(15);
		vBox.setPadding(new Insets(15, 15, 15, 15));
		vBox.getChildren().add(new Label("Courses"));
		
		Label[] courses = {new Label("CSCI 1301"), new Label("CSCI 1302"), new Label("CSCI 2410"), new Label("CSCI 3720")};
		
		for(Label course: courses) {
			VBox.setMargin(course, new Insets(0, 0, 0, 15));
			vBox.getChildren().add(course);
		}
		
		return vBox;
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d97jdefrtg2sejwf50cg.png)

The program defines the **getHBox()** method. This method returns an **HBox** that contains two buttons and an image view (lines 31–40). The background color of the **HBox** is set to gold using Java CSS (line 35). The program defines the **getVBox()** method. This method returns a **VBox** that contains five labels (lines 42–55). The first label is added to the **VBox** in line 45 and the other four are added in line 51. The **setMargin** method is used to set a node’s margin when placed inside the **VBox** (line 50).