Я написал FXML-файл, в котором использую пользовательский компонент, расширяющий Group. При загрузке этого пользовательского компонента он должен добавить некоторые дочерние элементы (здесь: MyOverlayIcon) в свой список дочерних элементов и установить некоторые атрибуты с помощью кода (здесь: layoutX и layoutY).
MyIcon.java:
public class MyIcon extends Group {
/********************************
* Graphic
********************************/
private ImageView graphic;
public ImageView getGraphic() {
if(graphic == null) {
graphic = new ImageView();
getChildren().add(graphic);
// Send image to back:
graphic.toBack();
}
return graphic;
}
/********************************
* DataPath
********************************/
private Property<String> dataPath;
public Property<String> dataPathProperty() {
if (dataPath == null) {
dataPath = new SimpleStringProperty();
}
return dataPath;
}
public String getDataPath() {
return dataPathProperty().getValue();
}
public void setDataPath(String dataPath) {
this.dataPathProperty().setValue(dataPath);
getGraphic().setImage(new Image(dataPath));
}
/********************************
* Overlays
********************************/
private ObservableList<MyOverlayIcon> overlays;
public ObservableList<MyOverlayIcon> getOverlays() {
if (overlays == null) {
overlays = FXCollections.observableArrayList();
overlays.addListener(new ListChangeListener<MyOverlayIcon>() {
@Override
public void onChanged(ListChangeListener.Change<? extends MyOverlayIcon> c) {
double moveX = 0.0;
double moveY = 0.0;
double iconWidth = 48.0;
double iconHeight = 48.0;
ObservableList<? extends MyOverlayIcon> icons = c.getList();
MyOverlayIcon icon = icons.get(icons.size() - 1);
String orientation = icon.getOrientation().toString();
if(orientation.endsWith("EAST")) {
moveX = iconWidth / 2;
}
if(orientation.startsWith("SOUTH")) {
moveY = iconHeight / 2;
}
icon.setLayoutX(moveX);
icon.setLayoutY(moveY);
getChildren().add(icon);
}
});
}
return overlays;
}
/********************************
* Constructor
********************************/
public MyIcon(){}
}
MyOverlayIcon.java:
public class MyOverlayIcon extends MyIcon {
private EnumOrientation orientation;
public EnumOrientation getOrientation() {
return orientation;
}
public void setOrientation(EnumOrientation orientation) {
this.orientation = orientation;
}
public MyOverlayIcon() {}
}
MyIconView.fxml:
<Group xmlns:fx="http://javafx.com/fxml">
<MyIcon dataPath="@/images/User1_48.png">
<overlays>
<MyOverlayIcon dataPath="@/images/Remove_24.png" orientation="SOUTHWEST" />
<MyOverlayIcon dataPath="@/images/Search1_24.png" orientation="NORTHEAST" />
</overlays>
</MyIcon>
</Group>
Когда я запускаю приложение в своей IDE, загружая этот файл fxml с помощью FXMLLoader, оно работает нормально: все новые дочерние элементы добавляются и отображаются правильно:
Теперь я хочу изменить этот файл fxml с помощью Scene Builder. Но когда я загружаю файл с помощью Scene Builder, я вижу только пустой экземпляр группы:
Только эти два обходных пути я узнал:
1.) Вызов метода, который добавляет дочерние элементы в список дочерних элементов явно (например, внутри метода установки свойства), дочерние элементы добавляются и отображаются, но только при вызове этого сеттера путем изменения чего-либо, а не в начале, когда файл был загружен.
2.) Запустив Scene Builder в режиме отладки, я обнаружил, что любой атрибут, который я хочу изменить программно, должен быть сначала указан в fxml. В противном случае Scene Builder устанавливает значение по умолчанию.
Например, дети, которые я добавил динамически с помощью java-кода, один раз добавляются и снова удаляются, если компонент не указал никаких дочерних узлов в fxml. При добавлении любого пустого узла, такого как Pane, к моему компоненту в fxml, дочерние элементы не будут удалены, а также будут отображаться в Scene Builder.
С другими атрибутами все точно так же: значения, которые должны быть установлены кодом (здесь: layoutX и layoutY), применяются только в том случае, если я устанавливаю их в файле fxml с любым значением.
MyIconView_Workaround.fxml:
<Group xmlns:fx="http://javafx.com/fxml">
<MyIcon dataPath="@/images/User1_48.png">
<Pane />
<overlays>
<MyOverlayIcon dataPath="@/images/Remove_24.png" orientation="SOUTHWEST" layoutY="456">
<Pane />
</MyOverlayIcon>
<MyOverlayIcon dataPath="@/images/Search1_24.png" orientation="NORTHEAST" layoutX="123">
<Pane />
</MyOverlayIcon>
</overlays>
</MyIcon>
</Group>
//Изменить: если вы не видите связанные изображения, попробуйте эту ссылку на галерею .
У кого-нибудь есть идея, как загрузить файл fxml с помощью Scene Builder, содержащего пользовательский компонент, который динамически добавляет дочерние элементы с помощью java-кода к себе и изменяет их (или его) значения атрибутов, не указывая их в fxml?