Search code examples
javajavafxclonepass-by-value

How to clone a node in the scene graph in JavaFX?


I have a HBox with prefHeight = 70 // no prefWidth or any width...

I also have a Pane with prefWidth = 50 // no prefHeight or any height...

I just want to add multiple instance of the pane to the HBox using some loop.

When I do add(pane) in the loop body it gives following error.

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = HBox[id=myHBox]

I need to find way to clone the pane(as it passes by value). Can anybody help me please? (taking snapshot are not work for me because prefHeight of the pane is not set/ computed using parent)


Solution

  • This error happens because you're trying to add the same instance of a Node to another Node. If you remove the comments from the example below you'll get that error as well. Loop, on the other hand, will work fine because in each iteration new Button instance is created.

    @Override
    public void start(Stage stage) {
        FlowPane root = new FlowPane();
    
        // Results in error
        // Button b1 = new Button("Button");
        // root.getChildren().addAll(b1,b1);
    
        for (int i = 0; i < 4; i++) {
            Button b = new Button("Button");
            root.getChildren().add(b);
        }
    
        Scene scene = new Scene(root, 50, 100);
    
        stage.setScene(scene);
        stage.show();
    }
    

    Your pane is probably more complicated, but you have to use the same principle. Put the code responsible for creating your pane in a separate method, getPane() or such, and use it in a loop to obtain new instances.

    JavaFX doesn't give you an out-of-the-box solution to make a deep copy of a Node. If your Node is crated statically you can:

    1. Put the code responsible for creating it in a separate method and use it throughtout your application every time you need to get a new instance of your pane.
    2. Define it in a FXML file and load it every time you need a new instance.

    Things get significantly worse if your Node has properties or children that were created or modified dynamically by the user. In that case you have to inspect its elements and recreate them on your own.