首页 文章

JavaFX - 为什么多次向窗格添加节点或向不同的窗格添加节点会导致错误?

提问于
浏览
2

我现在正在学习基本的JavaFX,我不理解我正在阅读的书中的这句话:“不,像文本字段这样的节点只能添加到一个窗格中一次 . 添加一个节点到一个窗格多次或不同的窗格将导致运行时错误 . “我可以从UML图中看到本书提供的它是一个组合,但我不明白为什么(库类代码实现) .

例如,为什么会导致编译错误?不是在窗格中实例化的新文本字段,因为它是一个组合?

FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf);

另外,为什么以下运行但不显示放置在窗格中的文本字段?

FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane2.getChildren().add(tf);

primaryStage.setScene(new Scene(pane));
primaryStage.show();

2 回答

  • 2

    试试这个:

    TextField tf = new TextField();
    TextField tf2 = new TextField();
    pane.getChildren().add(tf);
    pane.getChildren().add(tf2);
    

    您无法两次添加同一节点的原因是,只能在gui中查看具有相同规格和尺寸的一个节点 . 这就像将相同的蓝色圆圈复制到原始蓝色圆圈上一样 . 对于用户来说它看起来是一样的,但它会占用更多内存 .

  • 0

    这基本上是API设计方式的(有意)结果 . 每个 Node 都有一个属性集合,包括 parent 属性(场景图中的一个且只有一个 - 节点的父节点),以及 layoutXlayoutY 等属性,这些属性是节点相对于其父节点的坐标 . 因此,节点只能属于一个父节点,并且只能添加到父节点一次(因为它只能在父节点中有一个位置) . 以这种方式组织事物可以实现非常有效的布局过程 .

    另一种思考方式:假设你的第一个代码块做了你想要的;所以文本字段 tf 在流窗格中出现了两次 . 你期望从 tf.getBoundsInParent() 获得什么结果?由于 tf 在父级中出现两次,因此API无法为此调用提供合理的值 .

    您在问题中的陈述中有一些不准确之处:

    例如,为什么会导致编译错误?不是在窗格中实例化的新文本字段,因为它是一个组合?

    首先,从技术上讲,这是聚合,而不是组合;虽然我不确定理解差异会帮助你理解目前发生的事情 .

    其次,这里没有编译错误;你在运行时得到一个错误( pane 检测到相同的 node 已被添加两次;编译器无法检查这个) .

    第三,父母不会实例化您添加到它们的节点的副本 . 如果是这样,您将无法更改显示的节点的属性 . 例如,如果示例中的 FlowPane 在您调用 pane.getChildren().add(tf); 时实例化了一个新的 TextField ,然后显示了该新文本字段,那么如果您随后调用了 tf.setText("new text") ,则它将无效,因为它不会更改文本的文本 pane 正在显示的字段 .

    当您调用 pane.getChildren().add(...) 时,您将传递对要添加的节点的引用;然后,该节点将显示为窗格的子节点 . 任何其他实现都会产生非常反直觉的行为 .

    在你的第二个代码块中:

    pane.getChildren().add(tf);
    pane2.getChildren().add(tf);
    

    第二个调用隐式将 tfparent 属性设置为 pane2 ;因此 tf 不再是 pane 的孩子 . 因此,此代码具有从第一个父级 pane 中删除 tf 的效果 . 据我所知,这种副作用没有记录,所以你可能应该避免编写这样的代码 .

相关问题