JavaFx: parent.lookup returns null

2020-04-11 19:10发布

问题:

I use osgi+cdi and I have the following code:

Parent parent=null;
FXMLLoader fxmlLoader=getFxmlLoader();
try {
    parent = (Parent)fxmlLoader.load(getFxmlStream("tasklist.fxml"));
} catch (IOException ex) {
    Logger.getLogger(TestGoView.class.getName()).log(Level.SEVERE, null, ex);
}
ComboBox comboBox=(ComboBox) parent.lookup("#testComboBox");
if (comboBox==null){
    System.out.println("COMBOBOX NULL");
}else{
    System.out.println("COMBOBOX NOT NULL");
}

And I have the following tasklist.fxml

<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="440.0" prefWidth="757.0" xmlns="http://javafx.com/javafx/8.0.60-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.techsenger.testgo.core.adm.task.list.TaskDirListController">
   <children>
      <HBox>
         <children>
            <ToolBar maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" nodeOrientation="RIGHT_TO_LEFT" HBox.hgrow="SOMETIMES">
               <items>
                  <ComboBox fx:id="testComboBox" maxWidth="1.7976931348623157E308" nodeOrientation="LEFT_TO_RIGHT" />
               </items>
            </ToolBar>
         </children>
      </HBox>
   </children>
</VBox>

However parent.lookup("#testComboBox") returns null. How to explain it? I've checked the name of ID several times.

回答1:

Instead of using a lookup, which will only work after the scene has been rendered, you can put the logic you need in your controller class. You can inject elements from the FXML file into the controller class by annotating them @FXML.

public class TaskDirListController {

    @FXML
    private ComboBox<...> testComboBox ;

    public void initialize() {
        System.out.println(testComboBox);
    }

    // ...
}

Lookups are generally not robust, and I would recommend avoiding using them. If you really need to access something defined in the FXML file from a class other than the controller, the first thing to do is to consider reorganizing things so that you don't need to do this: it really indicates that your overall design is wrong.

If you really need this for some reason, it's better to use the FXMLLoader's namespace than a lookup:

Parent parent=null;
FXMLLoader fxmlLoader=getFxmlLoader();
try {
    parent = (Parent)fxmlLoader.load(getFxmlStream("tasklist.fxml"));
    ComboBox<?> comboBox = (ComboBox<?>) fxmlLoader.getNamespace().get("testComboBox");
    System.out.println(comboBox);
} catch (IOException ex) {
    Logger.getLogger(TestGoView.class.getName()).log(Level.SEVERE, null, ex);
}


回答2:

It is because you are trying to use lookup before showing the parent on the screen.

Pane root = FXMLLoader.load(getClass().getResource("tasklist.fxml"));

System.out.println(root.lookup("#testComboBox")); //returns  null
primaryStage.setScene(new Scene(root));
primaryStage.show();
System.out.println(root.lookup("#testComboBox")); //returns 
// ComboBox[id=testComboBox, styleClass=combo-box-base combo-box]


标签: java javafx