cyber101
cyber101

Reputation: 2994

JavaFX unable to find node declared in FXML at runtime using ID

Im unable to find a node "VBox" with id "#mainScrollPaneVbox" declared in FXML.

Here is my FXML:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.conuretech.video_assembler.FXMLController">
   <top>
      <MenuBar prefHeight="16.0" prefWidth="600.0" BorderPane.alignment="CENTER">
        <menus>
          <Menu mnemonicParsing="false" text="File">
            <items>
              <MenuItem mnemonicParsing="false" onAction="#handleNewAction" text="New" />
              <MenuItem mnemonicParsing="false" onAction="#handleOpenProjectAction" text="Open Project" />
              <MenuItem mnemonicParsing="false" onAction="#handleSaveAsAction" text="Save As..." />
              <MenuItem mnemonicParsing="false" onAction="#handleSaveAction" text="Save..." />
              <MenuItem mnemonicParsing="false" onAction="#handleCovertImagesToVideoAction" text="Convert Project To video" />
              <MenuItem mnemonicParsing="false" onAction="#handleImportLocalAction" text="Import Local Images" />
              <MenuItem mnemonicParsing="false" onAction="#handleImportRemoteAction" text="Import Remote Images" />
              <MenuItem mnemonicParsing="false" onAction="#handleExitAction" text="Exit" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Edit">
            <items>
              <MenuItem mnemonicParsing="false" text="Add New Frame From" />
               <MenuItem mnemonicParsing="false" text="Delete Current Frame" />
               <MenuItem mnemonicParsing="false" text="Edit Frame Properties" />
               <MenuItem mnemonicParsing="false" text="Video Properties" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" text="About" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
   </top>
   <left>
      <ScrollPane id="#mainScrollPane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <content>
            <VBox id="#mainScrollPaneVbox" prefHeight="200.0" prefWidth="200.0" />
         </content></ScrollPane>
   </left>
   <center>
      <GridPane BorderPane.alignment="CENTER">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
      </GridPane>
   </center>
</BorderPane>

Here is the Java code, that attempts to find the "Vbox" at runtime:

VBox vbox = (VBox) MainApp.scene.lookup("#mainScrollPaneVbox");

I also tried :

VBox vbox = (VBox) MainApp.scene.lookup("mainScrollPaneVbox");

But this still returns null.

Any ideas?

Thanks

Upvotes: 0

Views: 976

Answers (1)

James_D
James_D

Reputation: 209330

Why your code doesn't work

The id attribute in the FXML should contain just the id of the node, not the CSS lookup for the id. In other words, you have

<VBox id="#mainScrollPaneVbox" ... >

when you need

<VBox id="mainScrollPaneVbox" ... >

The lookup should have the CSS lookup:

VBox vbox = (VBox) MainApp.scene.lookup("#mainScrollPaneVbox");

But I would not advise doing things this way anyway, especially since you already have a controller class.

Recommended Approach

CSS lookups are not very robust. They rely on String binding, and are not typesafe. Moreover, any errors will not be caught until the lookup is actually performed, which may be well after the application has been launched (e.g. when the user performs some action).

A better approach is to use @FXML injection. While these still rely on String binding and there is no compile-time type checking, errors will be caught when the FXML file is loaded, so any failures happen much earlier. This makes it much easier to detect and fix errors.

To use @FXML injection you would do

<VBox fx:id="mainScrollPaneVbox"

and then in your controller class:

public class FXMLController {

    @FXML
    private VBox mainScrollPaneVbox ; // same field name as the fx:id

    // ...

    public void initialize() {
        // popuplate mainScrollPaneVbox ...
        // can similarly be accessed in event handlers

        // ...
    }

    // ...
}

Upvotes: 1

Related Questions