JavaFX 2.0 + FXML - 查找行为奇怪

5

我希望通过Node#lookup()在使用FXMLoader加载的场景中找到一个VBox节点,但是我遇到了以下异常:

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

代码如下:

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 !!!"));
    }
}

<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>

我希望了解:

  1. 为什么查找方法返回的是 SplitPaneSkin$Content 而不是 VBox
  2. 还有其他方法可以获取 VBox 吗?

提前感谢。

2个回答

10

获取VBox引用最简单的方法是调用FXMLLoader#getNamespace()。例如:

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

请注意,您需要创建FXMLLoader的实例,并调用非静态版本的load()才能使此方法起作用:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("test.fxml"));
AnchorPane page = (AnchorPane) fxmlLoader.load();

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;
    

我已经在我的帖子中更新了一个简单的例子。我知道@FXML注解,但是由于id是自动生成的,所以我无法使用它。 - Philippe Jean
很好,它正常工作。我原本没想到FXMLoader会将它们分配与根子元素相同的ID。很高兴能看到Oracle JavaFX UI团队的QA技术领袖回答stackoverflow上的问题。非常感谢 - Philippe Jean
欢迎您,但请看一下下面Greg的回答。它看起来更清晰。 - Sergey Grinev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接