Задача
Невозможно добавить одно и то же Label
несколько раз в граф сцены. Это задокументировано Node
( выделение мое):
Узел может появляться не более одного раза в любом месте графа сцены. В частности, узел должен появляться не более одного раза во всех следующих случаях: в качестве корневого узла Scene
, дочерних элементов ObservableList
для Parent
или в качестве фрагмента Node
.
Граф сцены не должен иметь циклов. Цикл будет существовать, если узел является предком самого себя в дереве, учитывая упомянутые выше отношения Group
content ObservableList
, Parent
children ObservableList
и Node
clip.
Если программа добавляет дочерний узел к Parent
(включая Group
, Region
и т. Д.), И этот узел уже является дочерним по отношению к другому Parent
или корню Scene
, узел автоматически (и без вывода сообщений) удаляется из своего прежнего родителя. Если программа пытается изменить граф сцены любым другим способом, который нарушает вышеуказанные правила, возникает исключение, попытка модификации игнорируется, и Граф сцены восстанавливается в своем прежнем состоянии.
Выделенная часть объясняет, почему Label
появляется только один раз при использовании <fx:reference>
.
Решение
Единственное решение вашей проблемы - продублировать Label
. Для этого есть как минимум два варианта.
Использование <fx:copy>
Один из способов сделать это с помощью <fx:copy>
( выделение мое):
Элемент <fx:copy>
создает копию существующего элемента. Как и <fx:reference>
, он используется с атрибутом fx:id
или переменной сценария. Атрибут «source» элемента указывает имя объекта, который будет скопирован. Тип источника должен определять конструктор копирования, который будет использоваться для создания копии из исходного значения.
На данный момент ни один из классов платформы JavaFX не предоставляет такого конструктора копирования, поэтому этот элемент предоставляется в основном для использования разработчиками приложений. Это может измениться в будущем выпуске.
Как указано в документации, использование <fx:copy>
требует, чтобы класс имел конструктор копирования. В документации также говорится, что ни один из основных классов JavaFX не предоставляет конструкторы копирования. Это означает, что вам придется создать подкласс Label
и предоставить необходимый конструктор, как показано в ответе funkyjelly . Чтобы обеспечить актуальность свойств, вы можете связать свойства внутри конструктора:
public class CopyableLabel extends Label {
public CopyableLabel(CopyableLabel label) {
// You only mentioned the text, tooltip, and style properties
// in your question. Bind more properties as needed.
textProperty().bind(label.textProperty());
tooltipProperty().bind(label.tooltipProperty());
styleProperty().bind(label.styleProperty());
}
}
Таким образом, вам нужно только ввести «мастер» Label
, и любые обновления будут распространяться на все копии. Используя этот дизайн, вы должны иметь в виду, что связанные свойства не могут быть установлены напрямую; попытка установить связанное свойство приведет к исключениям. Возможно, вы захотите документировать, что конструктор будет связывать свойства, а не просто копировать значения.
Использовать привязки выражений
Другой вариант - связать необходимые свойства в файле FXML. Вы все равно будете создавать несколько Label
s, но вам нужно будет только ввести "master" Label
, как и раньше.
<VBox xmlns="http://javafx.com/javafx/" xmlns:fx="http://javafx.com/fxml/1">
<Label fx:id="master"/>
<Label text="${master.text}" tooltip="${master.tooltip}" style="${master.style}"/>
<Label text="${master.text}" tooltip="${master.tooltip}" style="${master.style}"/>
<Label text="${master.text}" tooltip="${master.tooltip}" style="${master.style}"/>
<!-- repeat as needed -->
</VBox>
Используется привязка выражений возможностей JavaFX FXML. Эта опция может загромождать файл FXML, но не требует создания подкласса Label
.