Architecture & DesignWorking with JavaFX UI Layouts

Working with JavaFX UI Layouts

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

UI layouts form the basis of an interface design wherein we generally place controls in a manner so that overall interface have a consistent look. Most GUI frameworks provide some sort of a support in the form of APIs to manage layouts irrespective of any programming language. JavaFX is no exception. It has a rich set of layouts that can be availed to leverage the richness and consistency of looks in the interface design.

JavaFX UI Layouts

Choosing the right layout forms the basis of UI design. The layout forms the work area where we basically place the UI controls. Imagine an empty wall; if we are to hang our favorite paintings, posters, a wall clock, and so forth, we need lay them out in a specific fashion such as horizontally, vertically in a tabular form, and the like. Each of these forms is actually a layout of a particular kind. The name layout suggests its type and how the specific layout will lay out the elements. However, laying out elements on an empty wall is simple because the arrangement is static. But, the layout in the display area of a computer is more complex. Here, the arrangement is dynamic because the elements are scaled dynamically according to the screen resolution or window resizing. Therefore, managing the layout of a UI has a lot of constraints associated with it; these constraints need to be addressed before giving a consistent look and feel. Fortunately, the APIs provided by JavaFX do most of the hard work and we can almost do away with them by setting bare minimum parameters. But, before getting into that, let’s see five of the most commonly used JavaFX layout classes.

Layout Description
javafx.scene.layout.HBox Lays out controls horizontally
javafx.scene.layout.Vbox Lays out controls vertically
javafx.scene.layout.FlowPane Lays out controls in a horizontal flow, wrapping nodes when space is needed
javafx.scene.layout.BorderPane Lays out controls in the following positions: top, bottom, left, right, and center
javafx.scene.layout.GridPane Lays out controls in a grid or tabular structure
Note:

This article uses plain and simple Java code to design the interface. There are other ways to design a JavaFX interface, such as using FXML. Also, there is designer software called JavaFX Scene Builder, which makes designing complex user interfaces quick and easy. The scribe believes that if one is familiar with designing an interface in hard Java code, learning other forms of interface design is almost a walk in the park. So, here we’ll focus mostly on hard-coded interface design.

The examples in this article only show the design aspect of the interface. Actual functionality of it, such as implementing business logic or user input events with respect to the interface, is out of the scope of this article.

The HBox Layout

The HBox lays out controls horizontally in a row. We simply can add one child node at a time with the add() method or choose to add all child nodes with the single method called addAll(). The layout automatically adjusts the space occupied by the nodes according to their sizes. In case the parent node is non-re sizable, such as the Group node, the row size of the layout takes on the size of the greatest child node. Nodes are aligned at the top-left position by default, but they can be changed by the Pos enum constants such as: Pos.TOP_LEFT, Pos.TOP_RIGHT, Pos.LEFT_CENTER, and so forth. Other constraints that can be manipulated are: padding, margin, border, spacing, and the like. Here is a quick example to illustrate the idea.

package org.mano.example;

import javafx.application.Application;
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.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class LayoutDemo extends Application {

   public static void main(String[] args) {
      Application.launch(args);
   }

   @Override
   public void start(Stage stage) throws Exception {

      Scene scene = new Scene(createHBoxLayout(), 650, 100);
      stage.setTitle("Layout Demo");
      stage.setScene(scene);
      stage.show();
   }

   public HBox createHBoxLayout() {
      HBox hbox = new HBox();

      hbox.setSpacing(10);
      hbox.setPadding(new Insets(5));
      hbox.setAlignment(Pos.CENTER_LEFT);

      Label userLabel=new Label("User Name ");
      Label passLabel=new Label("Password ");
      TextField userTextField=new TextField();
      PasswordField passwordField=new PasswordField();
      Button loginButton=new Button("Login");

      hbox.getChildren().addAll(userLabel,userTextField,
         passLabel,passwordField,loginButton);

      return hbox;
   }
}

Listing 1: JavaFX code to implement a HBox layout

The controls are arranged horizontally in a HBox layout
Output 1: The controls are arranged horizontally in a HBox layout

The VBox Layout

The Vbox layout is very similar to the Hbox layout except that the child nodes are arranged in a vertical column. The parameters and other constraints have a similar effect and can be manipulated like the example code in Listing 1. Here is a quick code snippet to illustrate the idea. Note that the code is almost same as stated in the preceding example.

public class LayoutDemo extends Application {

   public static void main(String[] args) {
      // ...
   }

   @Override
   public void start(Stage stage) throws Exception {

      Scene scene = new Scene(createVBoxLayout(), 250, 200);
      // ...
   }

   public VBox createVBoxLayout() {
      VBox vbox = new VBox();

      vbox.setSpacing(10);
      vbox.setPadding(new Insets(5));
      vbox.setAlignment(Pos.CENTER_LEFT);

      // ...

      vbox.getChildren().addAll(userLabel,userTextField,
         passLabel,passwordField,loginButton);

      return vbox;
   }
}

Listing 2: JavaFX code to implement a VBox layout

The controls are arranged vertically in a VBox layout
Output 2: The controls are arranged vertically in a VBox layout

The FlowPane Layout

The nodes in the FlowPane layout are arranged in a horizontal sequence by default and wrap to the next line when the horizontal space cannot accommodate all the nodes. This flow-based layout can also be furnished in a vertical sequence by setting the orientation property either during instantiation of the layout class or later, through the setOrientation() method. There are many other properties that can be set, such as margin, border, vertical/horizontal gaps between nodes, alignment, wrap length, and so forth. Here is a quick example to illustrate a few of these parameters.

public class LayoutDemo extends Application {

   public static void main(String[] args) {
      // ...
   }

   @Override
   public void start(Stage stage) throws Exception {

      Scene scene = new Scene(createFlowPane(), 250, 200);
      // ...
   }

   public FlowPane createFlowPane(){

      FlowPane flowPane=new FlowPane();
      flowPane.setHgap(10);
      flowPane.setAlignment(Pos.CENTER_LEFT);


      Label userLabel=new Label("User Name ");
      Label passLabel=new Label("Password ");
      TextField userTextField=new TextField();
      PasswordField passwordField=new PasswordField();
      Button loginButton=new Button("Login");

      flowPane.getChildren().addAll(userLabel,userTextField,
         passLabel,passwordField,loginButton);

      return flowPane;
   }

}

Listing 3: JavaFX code to implement a FlowPane layout

The controls wrapped to the next line in a FlowPane layout
Output 3: The controls wrapped to the next line in a FlowPane layout

The BorderPane Layout

This is the most commonly used layout of all and, in practice, forms the basis of all other layouts while designing. It segments the display area into five regions: left, top, right, bottom, and center. Each region can hold only one node. Therefore, developers nest other layouts and set them in a particular region. We can set the layout with UI controls as follows.

package org.mano.example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class LayoutDemo extends Application {

   public static void main(String[] args) {
      Application.launch(args);
   }

   @Override
   public void start(Stage stage) throws Exception {

      Scene scene = new Scene(createBorderPane(), 250, 200);
      stage.setTitle("Layout Demo");
      stage.setScene(scene);
      stage.show();
   }


   public BorderPane createBorderPane() {

      BorderPane borderPane = new BorderPane();

      MenuBar menuBar = new MenuBar();
      Menu fileMenu = new Menu("File");
      fileMenu.getItems().addAll(new MenuItem("New"),
         new SeparatorMenuItem(), new MenuItem("Open"),
         new MenuItem("Save"), new MenuItem("Save As..."),
         new SeparatorMenuItem(), new MenuItem("Exit"));
      Menu editMenu = new Menu("Edit");
      editMenu.getItems().addAll(new MenuItem("Undo"),
         new MenuItem("Redo"), new MenuItem("Cut"),
         new MenuItem("Copy"), new MenuItem("Paste"),
         new SeparatorMenuItem(), new MenuItem("Search/Replace"));
      Menu helpMenu = new Menu("Help");
      helpMenu.getItems().addAll(new MenuItem("Help Contents"),
         new SeparatorMenuItem(), new MenuItem("About..."));
      menuBar.getMenus().addAll(fileMenu, editMenu, helpMenu);

      ToolBar toolbar = new ToolBar(new Button("New"),
         new Button("Open"), new Separator(), new Button("Cut"),
         new Button("Copy"), new Button("Paste"));

      VBox vbox = new VBox();
      vbox.getChildren().addAll(menuBar, toolbar);

      TreeItem<String> ti = new TreeItem<>("Projects");
      ti.getChildren().addAll(
         new TreeItem<String>("Project 1"),
         new TreeItem<String>("Project 2"),
         new TreeItem<String>("Project 3"),
         new TreeItem<String>("Project 4"));
      TreeView<String> tv = new TreeView<String>(ti);

      TabPane tabPaneLeft = new TabPane();
      Tab tab1 = new Tab("Project List");
      tab1.setContent(tv);
      tabPaneLeft.getTabs().addAll(tab1, new Tab("Explorer"));

      TabPane tabPaneRight = new TabPane();
      tabPaneRight.getTabs().addAll(new Tab("Outline"),
         new Tab("Task List"));

      borderPane.setTop(vbox);
      borderPane.setLeft(tabPaneLeft);
      borderPane.setCenter(new TextArea());
      borderPane.setRight(tabPaneRight);
      borderPane.setBottom(new Label("Status text:
         Borderpane demo"));

     return borderPane;
   }
}

Listing 4: JavaFX code to implement a BorderPane layout

Illustrating nodes set in five regions of a BorderPane layout Output 4: Illustrating nodes set in five regions of a BorderPane layout

The GridPane Layout

The GridPane layout is the most common layout used in constructing user input forms. This is one of the advanced layouts where we can specify row, column, and cell constraints. The structure typically resembles a table where we set nodes as its children. This tabular form can be customized to fit the controls, such as by spanning the column or row, setting up the background, and specifying the gap between rows and columns. With this layout, we can furnish a complex user interface with nesting other layouts. Listing 5 shows how we manipulate the properties to fit our needs.

package org.mano.example;

import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.*;
import javafx.stage.Stage;

public class LayoutDemo extends Application {

   public static void main(String[] args) {
      Application.launch(args);
   }

   @Override
   public void start(Stage stage) throws Exception {

      GridPane root = new GridPane();
      FlowPane leftbanner = new FlowPane();
      leftbanner.setPrefWidth(200);
      String bgStyle = "-fx-background-color: lightblue;"
         + "-fx-background-radius: 0%;"
         + "-fx-background-inset: 5px;";
         leftbanner.setStyle(bgStyle);

         root.add(leftbanner, 0, 0, 1, 1);
         root.add(createGridPane(), 1, 0, 1, 1);
         Scene scene = new Scene(root, 550, 300);
         stage.setTitle("Layout Demo");
         stage.setScene(scene);
         stage.show();
   }

   public GridPane createGridPane() {
      GridPane grid = new GridPane();
      grid.setPadding(new Insets(10));
      grid.setHgap(10);
      grid.setVgap(10);

      Text txt = new Text("Name and Location");
      txt.setFont(Font.font("Dialog", FontWeight.BOLD, 12));

      grid.add(txt, 0, 0, 1, 1);
      grid.add(new Separator(), 0, 1, 3, 1);

      grid.add(new Label("Project Name:"), 0, 2, 1, 1);
      grid.add(new TextField(), 1, 2, 1, 1);

      grid.add(new Label("Project Location:"), 0, 3, 1, 1);
      grid.add(new TextField(), 1, 3, 1, 1);
      grid.add(new Button("Browse..."), 2, 3, 1, 1);

      grid.add(new Label("Project Folder:"), 0, 4, 1, 1);
      grid.add(new TextField(), 1, 4, 1, 1);

      grid.add(new Separator(), 0, 5, 3, 1);

      grid.add(new Label("JavaFX Platform:"), 0, 6, 1, 1);
      ComboBox<String> cb = new ComboBox<>();
      cb.setPrefWidth(400);
      grid.add(cb, 1, 6, 1, 1);
      grid.add(new Button("Manage Platforms..."), 2, 6, 1, 1);

      grid.add(new CheckBox("Create Custom Preloader"), 0, 7, 3, 1);

      grid.add(new Label("tProject Name:"), 0, 8, 1, 1);
      grid.add(new TextField(), 1, 8, 1, 1);

      grid.add(new Separator(), 0, 9, 3, 1);

      grid.add(new CheckBox("Use Dedicated Foldr for storing "
         + "Libraries"), 0, 10, 3, 1);

      grid.add(new Label("tLibraries Folder:"), 0, 11, 1, 1);
      grid.add(new TextField(), 1, 11, 1, 1);
      grid.add(new Button("Browse..."), 2, 11, 1, 1);

      grid.add(new Label("Different users and projects can "
         + "share the same compilation librariesn"
         + "(see Help for details)"),1, 12, 1, 1);

      grid.add(new CheckBox("Create Application Class"), 0, 13, 1, 1);
      grid.add(new TextField(), 1, 13, 1, 1);

      grid.add(new CheckBox("Set as Main Project"), 0, 14, 1, 1);

      grid.add(new Separator(), 0, 15, 3, 1);

      FlowPane fp = new FlowPane(Orientation.HORIZONTAL, 10, 10);
      fp.setAlignment(Pos.CENTER_RIGHT);
      fp.getChildren().addAll(
         new Button("< Back"),
         new Button("Next >"),
         new Button("Finish"),
         new Button("Cancel"),
         new Button("Help"));
      grid.add(fp, 0, 16, 3, 1);

      return grid;
   }
}

Listing 5: JavaFX code to implement a GridPane layout

Interface designed using GridPane layouts (this is a kind of interface we see while creating a JavaFX Application in NetBeans)
Output 5: Interface designed using GridPane layouts (this is a kind of interface we see while creating a JavaFX Application in NetBeans)

Conclusion

Undoubtedly, a JavaFX layout in comparison with Swing layouts is a significant improvement over its design. It is not only easy but also seems more intuitive in terms of its implementation. It requires less code and can be quickly set up with the required properties to get a desired format of laying out UI controls. Seemingly, it still lacks the simplicity and elegance provided by QtJambi. QtJambi is Qt C++ Framework’s reciprocal to Java GUI development. Although JavaFX is feature rich, the core GUI framework of QtJambi seems to be much better than JavaFX, even though their paradigm of built architecture is entirely different.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories