为什么Tab在将内容设置为其他内容之前需要将内容设置为null?

时间:2017-09-19 21:52:57

标签: javafx

目标是使用BorderPane的内容切换Tab的内容,反之亦然,以创建一种方法来最大化"标签。 出于某种原因,我必须在将Tab设置为真实内容之前将其内容设置为null。

这是一个MCVE:

public class FXTests extends Application {

    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();        
        Scene scene = new Scene(root, 300, 250);

        Rectangle content = new Rectangle(100, 100, Paint.valueOf("red"));
        Tab tab = new Tab("tab1", content);
        TabPane tabPane = new TabPane(tab);        
        root.setCenter(tabPane);

        Button switchContent = new Button("fill");
        switchContent.setOnAction((e) -> {
            if(switchContent.getText().equals("fill"))
            {
                root.setCenter(tab.getContent());

                switchContent.setText("restore");
            }else
            {                
                root.setCenter(tabPane); 
                System.out.println(tab.getContent());
                tab.setContent(null); //why is this required?
                tab.setContent(content);

                switchContent.setText("fill");
            }
        });
        root.setTop(switchContent);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

我做错了吗? 这是JavaFX中的错误还是预期的行为?

Java版本:1.8.0_141

1 个答案:

答案 0 :(得分:2)

来自Node文档:

  

如果程序将子节点添加到Parent(包括Group,Region等)并且该节点已经是不同Parent的子节点或Scene的根节点,则该节点将自动(并静默地)从其节点中删除前父母。

TabPane控件在内部由外观支持,在本例中,外观是包含节点层次结构的容器。当您按下“填充”按钮并将borderPane的中心设置为直接引用内容节点时,系统将以静默方式从选项卡的外观中删除内容。当您按下“恢复”按钮时,将显示选项卡窗格,其中没有内容(因为它被静默删除)。

看起来,从内容静默删除内容不会向选项卡控件对象提供通知,因此选项卡控件对象仍会显示对内容的引用,即使内容不再位于外观中也是如此。我的猜测是将选项卡内容的值设置为null,然后返回到内容,使选项卡更新外观层次结构以再次引用内容。

IMO,处理此问题的更好方法是在编码时要小心,并尝试确保永远不会触发静默删除节点。您可以通过在代码中显式删除节点来执行此操作(通过在将其设置为边框窗格中心之前从选项卡窗格中显式删除内容)。然后,您最终不会在选项卡窗格控件与其外观之间出现任何奇怪的内部状态不匹配。

这样的事情(它没有太大的不同,但对我来说更容易理解和解释):

Node tabContent = tab.getContent();

Button switchContent = new Button("fill");
switchContent.setOnAction((e) -> {
    if (switchContent.getText().equals("fill")) {
        tab.setContent(null);
        root.setCenter(tabContent);

        switchContent.setText("restore");
    } else {
        root.setCenter(tabPane);
        tab.setContent(tabContent);

        switchContent.setText("fill");
    }
});

请注意,上面的代码段假定标签内容已预先初始化并在标签中设置,并且您不会更改应用程序中其他位置的标签内容(如果这样做,那么您需要更加小心编码并在那里有更多的逻辑来处理这种外部变化。)