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.

What You'll Learn:
  • 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.

When to Use SplitPane:
  • 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>
SplitPane Attributes in Jukebox:
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

SplitPane Orientation Options:
  • 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>
Multiple Dividers:

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>
Each Section Contains:
  1. Title Label: Shows "Albums" or "Songs"
  2. 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
  3. HBox with Action Buttons: Add New and Delete buttons

Benefits of Using SplitPane in Admin Panel

Why SplitPane Works Well Here:
  1. Simultaneous Visibility: Users can see both albums and songs at the same time, making it easy to manage relationships between them
  2. 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
  3. Efficient Use of Space: The entire window height is used effectively without requiring scrolling to see both sections
  4. Clear Separation: The divider clearly separates the two functional areas, reducing visual clutter
  5. 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;
}
CSS Properties Explained:
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);
Working with Dividers:
  • 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:

    1. Run the Jukebox application and open the Admin Panel
    2. Notice the horizontal divider between Albums and Songs sections
    3. Try dragging the divider up and down to resize the sections
    4. Notice how the ListViews and edit fields resize with their sections
    5. Open admin-panel-view.fxml and find the SplitPane definition
    6. Change dividerPositions="0.5" to dividerPositions="0.3" and see how the layout changes
    7. Try changing orientation="VERTICAL" to orientation="HORIZONTAL" to see a side-by-side layout

    Common Pitfalls

    Pitfall 1: Forgetting to Set Divider Positions

    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.

    Pitfall 2: Nested SplitPanes Can Be Confusing

    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.

    Pitfall 3: Minimum Size Issues

    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.

    Pitfall 4: Missing fx:id for Items

    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.

    Pitfall 5: Not Using VBox.vgrow or HBox.hgrow

    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

    Related Cookbook Sections