【问题标题】:JavaFX - Why does adding a node to a pane multiple times or to different panes result in an error?JavaFX - 为什么将节点多次添加到窗格或不同的窗格会导致错误?
【发布时间】:2015-02-26 02:01:59
【问题描述】:

我现在正在学习基本的 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();

【问题讨论】:

  • 这句话从何而来?一些上下文会很有用。
  • 来自教科书
  • 您可以查看 JavaFX 源代码并找出原因。
  • 你真的不需要看源代码。您可以查看API documentation 并发现允许这样做是没有意义的。例如,如果允许此代码,则 tf.getBoundsInParent() 等方法调用将没有有意义的语义。

标签: java javafx javafx-2


【解决方案1】:

这基本上是 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 的效果。据我所知,这种副作用没有记录在案,因此您可能应该避免编写这样的代码。

【讨论】:

    【解决方案2】:

    试试这个:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 2018-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多