I wrote an FXML-File where I use a custom component, extending Group. When loading this custom component, it should be adding some childs (here: MyOverlayIcon) to its children-list and set some attributes by code (here: layoutX and layoutY).
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(){}
}
public class MyOverlayIcon extends MyIcon {
private EnumOrientation orientation;
public EnumOrientation getOrientation() {
return orientation;
}
public void setOrientation(EnumOrientation orientation) {
this.orientation = orientation;
}
public MyOverlayIcon() {}
}
<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>
When I start the application in my IDE, loading this fxml file fith FXMLLoader, it works fine: all new children are added and displayed correctly:
Now I want to modify this fxml file with Scene Builder. But when I load the file with Scene Builder, I see just an empty group instance:
Only these two workarounds I found out:
1.) Calling the method that adds the children to the children-list explicitly (e.g. inside a setter-method of a property), the children are added and displayed, but only when calling this setter by modifying something and not at the start when the file has been loaded.
2.) With running Scene Builder in debug mode, I found out, that any attribute I want to modify programmaticly, has to been specified in fxml first. Otherwise, Scene Builder sets its value to the default value.
For exemple the children I added dynamicly by java-code, are once added and removed again, if the component hasn't specified any child nodes in fxml. Adding just any empty node like Pane to my component in fxml, the children won't be removed and are also displayed in Scene Builder.
With other attributes its just the same: The values that should be set by code (here: layoutX and layoutY) are only applied if I set them in fxml file with any value.
<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>
//Edit: If you can't see the linked images, try this gallery link.
Does anybody have got an idea how to load an fxml file with Scene Builder containing a custom component that adds children dynamicly by java-code to itself and modifies their (or its) attribute-values without specifing them in fxml?
I found this post on oracle forum from half a year ago.
There it's said, that this is a bug and I found out that in the newest version of scene builder (Scene Builder 1.1 Early Access) it is fixed.
With this version everything works fine as it should. :)
Thanks for your help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With