Using SplitPane
SplitPane is a JavaFX layout container that divides space between two or more resizable sections. Users can drag dividers to change the relative sizes of each section. In the Jukebox project, SplitPane is used in the Admin Panel to separate the albums section (top) from the songs section (bottom). This cookbook section explains how to work with SplitPane.
- SplitPane structure and orientation
- Adding items to a SplitPane
- Setting divider positions
- Using SplitPane in FXML
- Styling SplitPane with CSS
- SplitPane use cases and benefits
SplitPane Overview
SplitPane is ideal for creating user interfaces where users need to control the relative space allocated to different parts of the UI. Each section (called an "item") can contain any Node, and users can resize these sections by dragging the dividers between them.
- You have two or more related sections that users want to see simultaneously
- Users need to control the relative size of different UI areas
- You want a flexible layout that adapts to user preferences
- You have complex UI with multiple views that need independent scrolling
SplitPane in Jukebox: The Admin Panel
The Admin Panel in Jukebox uses a vertical SplitPane to separate albums (top) from songs (bottom). This allows users to see both the album list and the song list at the same time, while being able to adjust how much space each takes.
<!-- In admin-panel-view.fxml -->
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="600" prefWidth="800" VBox.vgrow="ALWAYS">
<items>
<VBox alignment="TOP_CENTER" spacing="10">
<!-- Albums section (top) -->
<children>
<Label text="Albums" />
<HBox alignment="CENTER_LEFT" spacing="20" VBox.vgrow="ALWAYS">
<ListView fx:id="albumsList" ... />
<VBox>...</VBox> <!-- Edit fields for albums -->
</HBox>
<HBox alignment="CENTER_LEFT" spacing="10">
<Button fx:id="addAlbumButton" ... />
<Button fx:id="deleteAlbumButton" ... />
</HBox>
</children>
</VBox>
<VBox alignment="TOP_CENTER" spacing="10">
<!-- Songs section (bottom) -->
<children>
<Label text="Songs" />
<HBox alignment="CENTER_LEFT" spacing="20" VBox.vgrow="ALWAYS">
<ListView fx:id="songsList" ... />
<VBox>...</VBox> <!-- Edit fields for songs -->
</HBox>
<HBox alignment="CENTER_LEFT" spacing="10">
<Button fx:id="addSongButton" ... />
<Button fx:id="deleteSongButton" ... />
</HBox>
</children>
</VBox>
</items>
</SplitPane>
| Attribute | Purpose | Value in Jukebox |
|---|---|---|
orientation |
Direction of the split (horizontal or vertical) | VERTICAL |
dividerPositions |
Initial position of dividers (0.0 to 1.0) | 0.5 (50% split) |
prefHeight/prefWidth |
Preferred dimensions | 600 / 800 |
VBox.vgrow |
Layout constraint for parent VBox | ALWAYS |
Understanding Orientation
HORIZONTAL- Divides space left to right (items side by side)VERTICAL- Divides space top to bottom (items stacked vertically)
<!-- Horizontal SplitPane - items side by side -->
<SplitPane orientation="HORIZONTAL">
<items>
<VBox>...</VBox> <!-- Left section -->
<VBox>...</VBox> <!-- Right section -->
</items>
</SplitPane>
<!-- Vertical SplitPane - items stacked vertically -->
<SplitPane orientation="VERTICAL">
<items>
<VBox>...</VBox> <!-- Top section -->
<VBox>...</VBox> <!-- Bottom section -->
</items>
</SplitPane>
Divider Positions
The dividerPositions attribute controls where the dividers are initially placed. For a SplitPane with 2 items, a single value between 0.0 and 1.0 specifies the position of the divider:
<SplitPane dividerPositions="0.3" ...>
<items>
<VBox>...</VBox> <!-- Gets 30% of the space -->
<VBox>...</VBox> <!-- Gets 70% of the space -->
</items>
</SplitPane>
<SplitPane dividerPositions="0.7" ...>
<items>
<VBox>...</VBox> <!-- Gets 70% of the space -->
<VBox>...</VBox> <!-- Gets 30% of the space -->
</items>
</SplitPane>
For a SplitPane with more than 2 items, dividerPositions takes a comma-separated list of values. For example, with 3 items:
<SplitPane dividerPositions="0.3,0.7" ...>
<items>
<VBox>...</VBox> <!-- Gets 30% of the space -->
<VBox>...</VBox> <!-- Gets 40% of the space (0.7 - 0.3) -->
<VBox>...</VBox> <!-- Gets 30% of the space -->
</items>
</SplitPane>
SplitPane Structure in Admin Panel
The Admin Panel's SplitPane contains two main VBox containers as its items. Each VBox has the same structure:
<SplitPane dividerPositions="0.5" orientation="VERTICAL" ...>
<items>
<!-- ALBUMS SECTION (Top) -->
<VBox alignment="TOP_CENTER" spacing="10">
<children>
<Label text="Albums" />
<HBox alignment="CENTER_LEFT" spacing="20" VBox.vgrow="ALWAYS">
<ListView fx:id="albumsList" prefHeight="200" prefWidth="300" HBox.hgrow="ALWAYS" />
<VBox alignment="TOP_LEFT" spacing="10">
<Label text="Name:" />
<TextField fx:id="albumNameField" promptText="Album name" />
<Label text="Artist:" />
<TextField fx:id="albumArtistField" promptText="Artist" />
<Label text="Genre:" />
<ComboBox fx:id="genreComboBox" prefWidth="150" promptText="Genre" />
</VBox>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="10">
<Button fx:id="addAlbumButton" onAction="#onAddAlbumClicked" text="Add New Album" />
<Button fx:id="deleteAlbumButton" onAction="#onDeleteAlbumClicked" text="Delete Album" />
</HBox>
</children>
</VBox>
<!-- SONGS SECTION (Bottom) -->
<VBox alignment="TOP_CENTER" spacing="10">
<children>
<Label text="Songs" />
<HBox alignment="CENTER_LEFT" spacing="20" VBox.vgrow="ALWAYS">
<ListView fx:id="songsList" prefHeight="200" prefWidth="300" HBox.hgrow="ALWAYS" />
<VBox alignment="TOP_LEFT" spacing="10">
<Label text="Title:" />
<TextField fx:id="songTitleField" promptText="Song title" />
<Label text="Length (seconds):" />
<TextField fx:id="songLengthField" promptText="Duration in seconds" />
</VBox>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="10">
<Button fx:id="addSongButton" onAction="#onAddSongClicked" text="Add New Song" />
<Button fx:id="deleteSongButton" onAction="#onDeleteSongClicked" text="Delete Song" />
</HBox>
</children>
</VBox>
</items>
</SplitPane>
- Title Label: Shows "Albums" or "Songs"
- HBox with ListView + Edit Fields:
- ListView displays the items (albums or songs)
- VBox contains edit fields (TextFields, ComboBox) for the selected item
VBox.vgrow="ALWAYS"makes this section expand vertically
- HBox with Action Buttons: Add New and Delete buttons
Benefits of Using SplitPane in Admin Panel
- Simultaneous Visibility: Users can see both albums and songs at the same time, making it easy to manage relationships between them
- User-Controlled Layout: Users can adjust the space based on their workflow - more space for albums if they're focused on album management, or more space for songs if they're editing song details
- Efficient Use of Space: The entire window height is used effectively without requiring scrolling to see both sections
- Clear Separation: The divider clearly separates the two functional areas, reducing visual clutter
- Consistent Structure: Both sections have the same structure (Label + ListView + Edit Fields + Buttons), making the UI predictable and easy to learn
SplitPane Styling in Jukebox
The Admin Panel's SplitPane is styled using CSS from application-window.css:
/* SplitPane styling */
.split-pane {
-fx-background-color: #121212;
-fx-border-color: #444;
-fx-border-width: 3;
-fx-border-radius: 8;
-fx-border-insets: 0;
}
.split-pane > *.split-pane-divider {
-fx-background-color: #ff8c00;
-fx-padding: 1;
}
.split-pane-divider {
-fx-background-color: #ff8c00;
-fx-padding: 1;
}
.split-pane-divider:hover {
-fx-background-color: #ffa726;
}
| Property | Purpose | Value |
|---|---|---|
-fx-background-color |
Background color of the SplitPane | #121212 (dark charcoal) |
-fx-border-color |
Border color | #444 (dark gray) |
-fx-border-width |
Border thickness | 3 pixels |
-fx-border-radius |
Rounded corners | 8 pixels |
-fx-background-color (divider) |
Divider color | #ff8c00 (amber/orange) |
-fx-background-color (divider hover) |
Divider color on hover | #ffa726 (lighter orange) |
Programmatic SplitPane Configuration
While Jukebox defines SplitPane in FXML, you can also configure it programmatically:
// Creating a SplitPane programmatically
SplitPane splitPane = new SplitPane();
// Set orientation
splitPane.setOrientation(Orientation.VERTICAL);
// Add items (nodes)
VBox topSection = new VBox(new Label("Top Section"));
VBox bottomSection = new VBox(new Label("Bottom Section"));
splitPane.getItems().addAll(topSection, bottomSection);
// Set divider positions
splitPane.setDividerPositions(0.5); // 50/50 split
// Or with multiple items
splitPane.getItems().add(new VBox(new Label("Another Section")));
splitPane.setDividerPositions(0.3, 0.7); // Positions for dividers
Handling Divider Position Changes
You can listen for when users move the dividers:
// Listen for divider position changes
splitPane.getDividers().get(0).positionProperty().addListener(
(obs, oldPos, newPos) -> {
System.out.println("Divider moved to: " + newPos);
// newPos is a value between 0.0 and 1.0
}
);
// You can also set positions programmatically
splitPane.getDividers().get(0).setPosition(0.6);
- Each divider in a SplitPane has a
positionProperty()that you can observe - For a SplitPane with N items, there are N-1 dividers
- Use
getDividers()to access all dividers - Positions are always between 0.0 (left/top) and 1.0 (right/bottom)
Creating Your Own SplitPane Layout
Let's create a simple SplitPane that divides a window into a left sidebar and a right main content area:
Step 1: Add SplitPane to FXML
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.SplitPane?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1">
<padding>
<Insets top="10" right="10" bottom="10" left="10"/>
</padding>
<children>
<SplitPane dividerPositions="0.2" orientation="HORIZONTAL" prefHeight="400" prefWidth="600" VBox.vgrow="ALWAYS">
<items>
<!-- Left Sidebar (20% width) -->
<VBox alignment="TOP_LEFT" spacing="10">
<children>
<Label text="Navigation" />
<ListView>
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Item 1" />
<String fx:value="Item 2" />
<String fx:value="Item 3" />
</FXCollections>
</items>
</ListView>
</children>
</VBox>
<!-- Right Main Content (80% width) -->
<VBox alignment="TOP_LEFT" spacing="10">
<children>
<Label text="Main Content" />
<Label text="This is the main content area." />
<Label text="It takes up 80% of the width." />
</children>
</VBox>
</items>
</SplitPane>
</children>
</VBox>
Step 2: Create Controller (if needed)
For a simple static layout, you might not need a controller. For dynamic content, create one:
public class MySplitPaneController {
public ListView<String> navigationList;
@FXML
private void initialize() {
// Initialize your SplitPane components
navigationList.getItems().addAll("Home", "Profile", "Settings");
}
}
Step 3: Use the SplitPane
Load and use your FXML as usual:
FXMLLoader loader = new FXMLLoader(
MySplitPaneController.class.getResource("/fxml/my-splitpane.fxml")
);
Parent root = loader.load();
// Add to your scene
Try This:
- Run the Jukebox application and open the Admin Panel
- Notice the horizontal divider between Albums and Songs sections
- Try dragging the divider up and down to resize the sections
- Notice how the ListViews and edit fields resize with their sections
- Open
admin-panel-view.fxmland find the SplitPane definition - Change
dividerPositions="0.5"todividerPositions="0.3"and see how the layout changes - Try changing
orientation="VERTICAL"toorientation="HORIZONTAL"to see a side-by-side layout
Common Pitfalls
If you don't set divider positions, SplitPane will distribute space equally among all items. This might not be what you want. Always set divider positions explicitly.
You can nest SplitPanes, but this can quickly become confusing for users. Each nested SplitPane adds another level of complexity. Consider using other layout containers if you only need a simple division.
SplitPane items can be resized to very small sizes, potentially making content unreadable. You can set minimum sizes on your items (like minimum width/height on VBox) to prevent this.
If you want to access the items in your controller, make sure to set fx:id on the nodes you add to the SplitPane's items list.
If your SplitPane is inside a VBox or HBox, use VBox.vgrow="ALWAYS" or HBox.hgrow="ALWAYS" to ensure the SplitPane expands to fill available space.
Key Takeaways
- SplitPane divides space between multiple resizable sections
- Use
orientationto control whether sections are horizontal or vertical - Use
dividerPositionsto set initial divider positions (0.0 to 1.0) - Users can drag dividers to resize sections at runtime
- SplitPane is ideal when users need to control relative space allocation
- In Jukebox, SplitPane separates albums (top) from songs (bottom) in Admin Panel
- Both sections have the same structure: Label + ListView + Edit Fields + Buttons
- SplitPane can be styled with CSS, including divider colors and hover effects
- You can listen to divider position changes programmatically