5

I want to find a VBox node in a scene loaded with FXMLoader thanks to Node#lookup() but I get the following exception :

java.lang.ClassCastException: com.sun.javafx.scene.control.skin.SplitPaneSkin$Content cannot be cast to javafx.scene.layout.VBox

The code :

public class Main extends Application {  
    public static void main(String[] args) {
        Application.launch(Main.class, (java.lang.String[]) null);
    }
    @Override
    public void start(Stage stage) throws Exception {
        AnchorPane page = (AnchorPane) FXMLLoader.load(Main.class.getResource("test.fxml"));
        Scene scene = new Scene(page);
        stage.setScene(scene);
        stage.show();

        VBox myvbox = (VBox) page.lookup("#myvbox");
        myvbox.getChildren().add(new Button("Hello world !!!"));
    }
}

The fxml file:

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" >
  <children>
    <SplitPane dividerPositions="0.5" focusTraversable="true" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
      <items>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
        <VBox fx:id="myvbox" prefHeight="398.0" prefWidth="421.0" />
      </items>
    </SplitPane>
  </children>
</AnchorPane>

I would like to know :
1. Why lookup method return a SplitPaneSkin$Content and not a VBox ?
2. How I can get the VBox in another manner ?

Thanks in advance

Philippe Jean
  • 317
  • 5
  • 12

2 Answers2

10

The easiest way to get a reference to the VBox is by calling FXMLLoader#getNamespace(). For example:

VBox myvbox = (VBox)fxmlLoader.getNamespace().get("myvbox");

Note that you'll need to create an instance of FXMLLoader and call the non-static version of load() in order for this to work:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("test.fxml"));
AnchorPane page = (AnchorPane) fxmlLoader.load();
Greg Brown
  • 111
  • 2
7
  1. SplitPane puts all items in separate stack panes (fancied as SplitPaneSkin$Content). For unknown reason FXMLLoader assign them the same id as root child. You can get VBox you need by next utility method:

    public <T> T lookup(Node parent, String id, Class<T> clazz) {
        for (Node node : parent.lookupAll(id)) {
            if (node.getClass().isAssignableFrom(clazz)) {
                return (T)node;
            }
        }
        throw new IllegalArgumentException("Parent " + parent + " doesn't contain node with id " + id);
    }
    

    and use it next way:

    VBox myvbox = lookup(page, "#myvbox", VBox.class);
    myvbox.getChildren().add(new Button("Hello world !!!"));
    
  2. you can use Controller and add autopopulated field:

    @FXML
    VBox myvbox;
    
Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141
  • I have updated my post with a simple example. I know `@FXML` annotation but I can't use it because ids are auto generated. – Philippe Jean Sep 08 '12 at 08:44
  • Great, it works fine. I had not supposed that FXMLoader assigned them the same id as root child. I'm glad to see QA tech lead in the JavaFX UI team at Oracle respond to stackoverflow questions. **Many thanks** – Philippe Jean Sep 08 '12 at 11:39
  • you are welcome, but take a look at Greg's answer below. It looks clearer. – Sergey Grinev Sep 08 '12 at 13:05