Это в основном (преднамеренное) следствие того, как проектируется API. Каждый Node
имеет набор свойств, включая свойство parent
(один и только один - родительский узел узла в графе сцены), а также такие свойства, как layoutX
и layoutY
, которые являются координатами узла относительно его родителя. Следовательно, узел может принадлежать только одному родителю и может быть добавлен только одному родителю один раз (поскольку он может иметь только одно местоположение в родительском элементе). Организация этого способа позволяет очень эффективный процесс компоновки.
Еще один способ подумать об этом: предположим, что ваш первый блок кода сделал то, что вы хотели; поэтому текстовое поле tf
появилось дважды в области потока. Какой результат вы ожидаете получить от tf.getBoundsInParent()
? Поскольку tf
появляется дважды в родительском, API не сможет дать разумного значения для этого вызова.
В заявлениях, которые вы делаете в своем вопросе, есть несколько неточностей:
Например, почему это приводит к ошибке компиляции? Не создается ли новое текстовое поле внутри панели, поскольку это композиция?
blockquote>Во-первых, технически это агрегирование, а не состав; хотя я не уверен, что различие поможет вам понять, что происходит на данный момент.
Во-вторых, здесь нет ошибки компиляции; вы получаете ошибку во время выполнения (
pane
обнаруживает, что один и тот жеnode
был добавлен дважды, у компилятора нет возможности проверить это).В-третьих, родители не создают копии узлов вы добавляете к ним. Если это так, вы не сможете изменить свойства отображаемых узлов. Например, если
FlowPane
в вашем примере создавал новыйTextField
, когда вы вызывалиpane.getChildren().add(tf);
, а затем отображал это новое текстовое поле, то, если вы впоследствии назоветеtf.setText("new text")
, это не повлияет, так как это будет не изменяйте текст текстового поля, отображаемогоpane
.Когда вы вызываете
pane.getChildren().add(...)
, вы передаете ссылку на узел, который хотите добавить; это тот узел, который затем отображается как дочерний элемент панели. Любая другая реализация создавала бы довольно противоречивое поведение.В вашем втором кодовом блоке:
pane.getChildren().add(tf); pane2.getChildren().add(tf);
второй вызов неявно устанавливает свойство
parent
вtf
наpane2
; следовательно,tf
уже не является дочерним элементомpane
. Таким образом, этот код имеет эффект удаленияtf
от первого родителя,pane
. Насколько мне известно, этот побочный эффект не документирован, поэтому вам, вероятно, следует избегать написания такого кода.