FX Experience Has Gone Read-Only

I've been maintaining FX Experience for a really long time now, and I love hearing from people who enjoy my weekly links roundup. One thing I've noticed recently is that maintaining two sites (FX Experience and JonathanGiles.net) takes more time than ideal, and splits the audience up. Therefore, FX Experience will become read-only for new blog posts, but weekly posts will continue to be published on JonathanGiles.net. If you follow @FXExperience on Twitter, I suggest you also follow @JonathanGiles. This is not the end - just a consolidation of my online presence to make my life a little easier!

tl;dr: Follow me on Twitter and check for the latest news on JonathanGiles.net.

We’ve introduced a SplitPane control in JavaFX 2.0, and today I thought I’d point out an interesting subtlety in the API. For the longest time our SplitPane API primarily consisted of the normal ‘left’ and ‘right’ (or ‘top’ and ‘bottom’) properties (indeed, the JavaDoc as of today still refers to this API). These were synonomous – if you set ‘top’ and ‘bottom’, they were literally copied to the ‘left’ and ‘right’ code, and our SplitPaneSkin just knew to draw with the items stacked vertically, rather than to lay them out horizontally.

In the very, very late stages of the JavaFX 2.0 EA program, we decided we didn’t really like this API all that much. The concept of having both left/right and top/bottom just didn’t really gel with us. After some discussion, we thought we’d use the same API style as we do elsewhere in JavaFX 2.0: expose a collection and allow for developers to place their content into it. This mean that to use a SplitPane, you’d use code such as the following:

import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class SplitPaneSample extends Application {

    @Override public void start(Stage stage) {
        HBox hbox = new HBox(20);
        hbox.setTranslateX(20);
        hbox.setTranslateY(20);

        SplitPane splitPane1 = new SplitPane();
        splitPane1.setPrefSize(200, 200);
        final Button l = new Button("Left Button");
        final Button r = new Button("Right Button");
        splitPane1.getItems().addAll(l, r);
        hbox.getChildren().add(splitPane1);

        Scene scene = new Scene(new Group(hbox), 560, 240);
        scene.setFill(Color.GHOSTWHITE);
        stage.setScene(scene);
        stage.setTitle("SplitPane");
        stage.setVisible(true);
    }

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

The main segment of code is the middle block, where we create a SplitPane, set a preferred size, and add in the two buttons we want to display. I hope you see where I’m going with this: now that we aren’t constrained to just having ‘left’ and ‘right’ nodes, we can actually put in any number of nodes into the items collection – and the SplitPane will automatically create N – 1 dividers. For example:

        SplitPane splitPane2 = new SplitPane();
        splitPane2.setPrefSize(300, 200);
        final Button l2 = new Button("Left Button");
        final Button c2 = new Button("Center Button");
        final Button r2 = new Button("Right Button");
        splitPane2.getItems().addAll(l2, c2, r2);
        hbox.getChildren().add(splitPane2);

The result of this code is shown in the second SplitPane you see in the picture above. Now, a SplitPane wouldn’t be all that great if it only allows for the SplitPane content to run in a horizontal flow, so we also support setting an orientation on the SplitPane. As mentioned, the default value is HORIZONTAL, which is what you see in the screenshot above. You can also set it to VERTICAL, which you can see in the screenshot below.

        SplitPane splitPane1 = new SplitPane();
        splitPane1.setOrientation(Orientation.VERTICAL);
        splitPane1.setPrefSize(200, 200);
        final Button l1 = new Button("Left Button");
        final Button r1 = new Button("Right Button");
        splitPane1.getItems().addAll(l1, r1);
        hbox.getChildren().add(splitPane1);

        SplitPane splitPane2 = new SplitPane();
        splitPane2.setOrientation(Orientation.VERTICAL);
        splitPane2.setPrefSize(300, 200);
        final Button l2 = new Button("Left Button");
        final Button c2 = new Button("Center Button");
        final Button r2 = new Button("Right Button");
        splitPane2.getItems().addAll(l2, c2, r2);
        hbox.getChildren().add(splitPane2);

Now, you can’t have a single SplitPane with multiple orientations. However, you can quite easily embed one SplitPane inside another to get this effect:

        SplitPane splitPane1 = new SplitPane();
        splitPane1.setOrientation(Orientation.VERTICAL);
        splitPane1.setPrefSize(200, 200);
        final Button l1 = new Button("Top Button");
        final Button r1 = new Button("Bottom Button");
        splitPane1.getItems().addAll(l1, r1);

        SplitPane splitPane2 = new SplitPane();
        splitPane2.setOrientation(Orientation.HORIZONTAL);
        splitPane2.setPrefSize(300, 200);
        final Button c2 = new Button("Center Button");
        final Button r2 = new Button("Right Button");
        splitPane2.getItems().addAll(splitPane1, c2, r2);
        hbox.getChildren().add(splitPane2);

With the code above, you’ll end up with something a little like this:

I hope this helps to introduce you to our brand new SplitPane control, and I look forward to see you using it in your applications soon!