As we've seen before, layout panes are JavaFX's way of organizing the various GUI elements of your application inside the window. For example, we've used HBox
to arrange elements beside each other, and BorderPane
to organize elements in specific areas of the window. We will be focusing on four layout panes:
Pane | Use |
---|---|
BorderPane |
Used to place elements in regions of the window, Top/Left/Center/Right/Bottom |
FlowPane |
Used to place elements next to each other until it runs out of room, then wraps around. Imagine text in Word or Pages wrapping at the end of a line. |
HBox |
Used to arrange elements in rows |
VBox |
Used to arrange elements in columns |
We'll look at each of these panes individually, but there are a few aspects of layout panes we need to examine first.
javafx.geometry.Pos
enumerationPos
allows us to set the alignment of Node
s within HBox
es and VBox
es. It is an enumeration, which is an ordered set of constants. You may remember the enum
declaration from C, like so:
typedef enum {
HEARTS,
DIAMONDS,
CLUBS,
SPADES
} CARD_SUIT;
Java enumerations work very much the same way:
public enum CARD_SUIT {
HEARTS, DIAMONDS, CLUBS, SPADES
}
CARD_SUIT suit = HEARTS;
They provide an easy interface to define types that are useful for categorization (like the suit of a playing card), but don't really need any data or methods defined on them. Additionally, they can be used to programmatically define a set of options, both those selected by a user or used only internally. Pos
defines various alignments within a layout pane, which fits both definitions!
Constant | V Alignment | H Alignment |
---|---|---|
Pos.TOP_LEFT |
Top | Left |
Pos.TOP_CENTER |
Top | Center |
Pos.TOP_RIGHT |
Top | Right |
Pos.CENTER_LEFT |
Center | Left |
Pos.CENTER |
Center | Center |
Pos.CENTER_RIGHT |
Center | Right |
Pos.BOTTOM_LEFT |
Bottom | Left |
Pos.BOTTOM_CENTER |
Bottom | Center |
Pos.BOTTOM_RIGHT |
Bottom | Right |
Pos.BASELINE_LEFT |
Baseline | Left |
Pos.BASELINE_CENTER |
Baseline | Center |
Pos.BASELINE_RIGHT |
Baseline | Right |
javafx.geometry.Insets
Let's see what this code produces:
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
public class BadDesign extends Application
{
private static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage)
{
// Making three buttons
Button btn1 = new Button();
btn1.setText("Button 1");
Button btn2 = new Button();
btn2.setText("Button 2");
Button btn3 = new Button();
btn3.setText("Button 3");
// We want an HBox with 10 pixels between the buttons!
// It will look great!
HBox hbox = new HBox(10, btn1, btn2, btn3);
Scene scene = new Scene(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
}
It's alright, but really want we want in addition is 10px of spacing around the entirety of each button. To do so, we can use the Insets
class to set the padding of the layout pane, or the spacing between the edges of the pane (in this case an HBox
), and the elements inside.
We can create Insets
in two ways:
// For uniform padding
hbox.setPadding(new Insets(10));
// To set the padding for each edge
// The order is Top/Right/Bottom/Left. To remember this, I use the mnemonic:
// TRouBLe
hbox.setPadding(new Insets(20, 10, 20, 10));
If we update our code from before:
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
public class BetterDesign extends Application
{
private static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage)
{
// Making three buttons
Button btn1 = new Button();
btn1.setText("Button 1");
Button btn2 = new Button();
btn2.setText("Button 2");
Button btn3 = new Button();
btn3.setText("Button 3");
// We want an HBox with 10 pixels between the buttons!
// It will look great!
HBox hbox = new HBox(10, btn1, btn2, btn3);
hbox.setPadding(new Insets(10));
Scene scene = new Scene(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
}
That's looking better! If we wanted, we could also use Insets
to set a margin around an individual element, like this:
hbox.setMargin(btn1, new Insets(10));
javafx.scene.control.Region
and javafx.scene.layout.Priority
Region
allows us to create empty spaces in our application between elements. Let's say we wanted an application with three buttons, but we wanted two on the left side of the window, and the third on the right. By placing a Region
element between the second and third buttons, and configuring it to grow to fill extra space, we can in essence model this behavior.
The Priority
enumeration is used to configure a node to grow to fill available space, either with HBox
's setHgrow()
or VBox
's setVgrow()
methods. By default, elements are configured to Priority.NEVER
, or never to grow to fill available space. There are two more options used:
Constant | Description |
---|---|
Priority.ALWAYS |
Always grow to fill available space |
Priority.SOMETIMES |
Grow to fill available space in the absence of a element using Priority.ALWAYS |
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
public class FloatingButtons extends Application
{
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage)
{
// Create the buttons
Button btn1 = new Button();
btn1.setText("Button 1");
Button btn2 = new Button();
btn2.setText("Button 2");
Button btn3 = new Button();
btn3.setText("Button 3");
// Create the spacer
Region spcr = new Region();
// Create the layout pane
HBox hbox = new HBox(10, btn1, btn2, spcr, btn3);
// Set margins around the buttons, since we only want extra space
// around them, not the spacer
hbox.setMargin(btn1, new Insets(10));
hbox.setMargin(btn2, new Insets(10));
hbox.setMargin(btn3, new Insets(10));
// Set the spacer to always grow horizontally.
hbox.setHgrow(spcr, Priority.ALWAYS);
Scene scene = new Scene(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
}
BorderPane
Method | Description |
---|---|
BorderPane() |
Creates an empty pane |
BorderPane(Node) |
Creates a pane with a Node at the center |
BorderPane(Node, Node, Node, Node, Node) |
Creates a pane with Node s in the following order: Center/Top/Right/Bottom/Left |
void setCenter(Node) |
Sets the center Node |
void setTop(Node) |
Sets the top Node |
void setRight(Node) |
Sets the right Node |
void setBottom(Node) |
Sets the bottom Node |
void setLeft(Node) |
Sets the left Node |
void setAlignment(Pos) |
Sets the alignment of Node elements |
static void setMargin(Node, Insets) |
Sets the margin of the specified child Node |
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
public class BorderPaneExample extends Application
{
// We'll show where all of the panes show up.
private static Button topBtn;
private static Button leftBtn;
private static Button ctrBtn;
private static Button rightBtn;
private static Button btmBtn;
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage)
{
topBtn = new Button("Top Button");
leftBtn = new Button("Left Button");
ctrBtn = new Button("Center Button");
rightBtn = new Button("Right Button");
btmBtn = new Button("Bottom Button");
BorderPane pane = new BorderPane(ctrBtn, topBtn, rightBtn, btmBtn, leftBtn);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.setTitle("BorderPane Example");
primaryStage.show();
}
}
javafx.scene.layout.FlowPane
FlowPane
s, whether in their horizontal or vertical flavors, arrange elements beside each other in a row or column until a specified width/height, then wraps around to the next row/column.
Method | Description |
---|---|
FlowPane() |
Creates an empty FlowPane with 0 for the horizontal and vertical gap |
FlowPane(double, double) |
Creates an empty FlowPane with a specified h- and v-gap |
FlowPane(double, double, Node...) |
Creates a FlowPane with a specified h- and v-gap and children |
FlowPane(Node...) |
Creates a FlowPane with specified children and 0 for the h- and v-gap |
FlowPane(Orientation) |
Creates a FlowPane with the specified orientation (Orientation.VERTICAL or .HORIZONTAL) and 0 for the h- and v-gaps |
FlowPane(Orientation, double, double) |
Creates a FlowPane with the specified orientation, h-, and v-gaps |
FlowPane(Orientation, double, double, Node...) |
Creates a FlowPane with the specified orientation, h-gap, v-gap, and children |
FlowPane(Orientation, Node...) |
Creates a FlowPane with the specified orientation and children |
ObservableList<Node> getChildren() |
Gets the children of the pane |
void setAlignment(Pos) |
Sets the alignment of the child nodes |
void setColumnAlignment(Pos) |
Sets the column (vertical) alignment of the child nodes |
void setHgap(double) |
Sets the horizontal gap |
void setOrientation(Orientation) |
Sets the orientation |
void setRowAlignment(Pos) |
Sets the row (horizontal) alignment of the child nodes |
void setVgap(double) |
Sets the vertical gap |
javafx.scene.layout.HBox
HBox
es arrange elements horizontally next to each other. Whenever you want a definite row, without wrapping, you should use an HBox
.
Method | Description |
---|---|
HBox() |
Creates a new, empty HBox |
HBox(double) |
Creates a new, empty HBox with a specified spacing |
HBox(Node...) |
Creates a new HBox with the specified children |
HBox(double, Node...) |
Creates a new HBox with the specified children and spacing |
ObservableList<Node> getChildren() |
Gets the children of the pane |
void setAlignment(Pos) |
Sets the alignment of the child nodes |
void setHgrow(Node, Priority) |
Set the growth behavior of a child node |
void setMargin(Node, Insets) |
Set the margin of a child node |
void setPadding(Insets) |
Sets the padding of the pane |
void setSpacing(double) |
Sets the spacing between elements in the pane |
javafx.scene.layout.VBox
VBox
es arrange vertically on top of each other. You should use a VBox
to position elements you want in a column.
Method | Description |
---|---|
VBox() |
Creates a new, empty VBox |
VBox(double) |
Creates a new, empty VBox with a specified spacing |
VBox(Node...) |
Creates a new VBox with the specified children |
VBox(double, Node...) |
Creates a new VBox with the specified children and spacing |
ObservableList<Node> getChildren() |
Gets the children of the pane |
void setAlignment(Pos) |
Sets the alignment of the child nodes |
void setVgrow(Node, Priority) |
Set the growth behavior of a child node |
void setMargin(Node, Insets) |
Set the margin of a child node |
void setPadding(Insets) |
Sets the padding of the pane |
void setSpacing(double) |
Sets the spacing between elements in the pane |