Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Load FXML files with custom components in JavaFX Scene Builder: Attributes are reset and children removed

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).

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>

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:

enter image description here

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:

enter image description here

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.

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>

enter image description here

//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?

like image 859
Daniel Avatar asked Nov 04 '22 00:11

Daniel


1 Answers

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!

like image 66
Daniel Avatar answered Nov 09 '22 22:11

Daniel