JavaFX – 为什么多次向窗格添加节点或向不同的窗格添加节点会导致错误?
我现在正在学习基本的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();
这基本上是API设计方式的(故意)结果。 每个Node
都有一组属性,包括parent
属性(场景图中的一个且只有一个 – 节点的父节点),以及layoutX
和layoutY
等属性,它们是节点相对于其父节点的坐标。 因此,节点只能属于一个父节点,并且只能添加到父节点一次(因为它只能在父节点中有一个位置)。 以这种方式组织事物可以实现非常有效的布局过程。
另一种思考方式:假设你的第一个代码块做了你想要的; 所以文本字段tf
在流程窗格中出现两次。 你期望从tf.getBoundsInParent()
获得什么结果? 由于tf
在父级中出现两次,因此API无法为此调用提供合理的值。
您在问题中的陈述中存在一些不准确之处:
例如,为什么会导致编译错误? 不是在窗格中实例化的新文本字段,因为它是一个组合?
首先,从技术上讲,这是聚合,而不是组合; 虽然我不确定理解差异会帮助你理解目前发生的事情。
其次,这里没有编译错误; 在运行时出现错误( pane
检测到同一node
已添加两次;编译器无法检查此情况)。
第三,父母不会实例化您添加到它们的节点的副本。 如果是这样,您将无法更改显示的节点的属性。 例如,如果示例中的FlowPane
在调用pane.getChildren().add(tf);
时实例化了一个新的TextField
pane.getChildren().add(tf);
,然后显示该新文本字段,然后如果您随后调用tf.setText("new text")
,它将没有任何效果,因为它不会更改pane
显示的文本字段的文本。
当你调用pane.getChildren().add(...)
你会传递一个对你想要添加的节点的引用; 然后,该节点将显示为窗格的子节点。 任何其他实现都会产生非常反直觉的行为。
在你的第二个代码块中:
pane.getChildren().add(tf); pane2.getChildren().add(tf);
第二个调用隐式将tf
的parent
属性设置为pane2
; 因此, tf
不再是pane
的孩子。 因此,此代码具有从第一个父pane
中删除tf
的效果。 据我所知,这种副作用没有记录,所以你可能应该避免编写这样的代码。
尝试这个:
TextField tf = new TextField(); TextField tf2 = new TextField(); pane.getChildren().add(tf); pane.getChildren().add(tf2);
您无法两次添加同一节点的原因是,只能在gui中查看具有相同规格和尺寸的一个节点。 这就像将相同的蓝色圆圈复制到原始蓝色圆圈上一样。 对于用户来说它看起来是一样的,但它会占用更多内存。