Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8148828

SplitPane Child Does Not Have null Parent After Being Removed

XMLWordPrintable

    • x86
    • windows_8

      FULL PRODUCT VERSION :
      Microsoft Windows [Version 6.3.9600]
      (c) 2013 Microsoft Corporation. All rights reserved.

      C:\Users\Owner>java -version
      java version "1.8.0_71"
      Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
      Java HotSpot(TM) Client VM (build 25.71-b15, mixed mode, sharing)

      C:\Users\Owner>

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.3.9600]
      (c) 2013 Microsoft Corporation. All rights reserved.

      C:\Users\Owner>ver

      Microsoft Windows [Version 6.3.9600]

      C:\Users\Owner>

      A DESCRIPTION OF THE PROBLEM :
      It is not possible to reparent a control that was in a SplitPane without first adding it and removing it from another layout pane. Even if you remove the control from the SplitPane and attempt to add it to a new scene in a Platform.runLater Runnable, the control will still have a reference to its old SplitPane parent long after being removed.

      This issue makes it difficult to make it so that you can drag controls out of a split pane and move them to a new scene. Because when you go to add the control to a new scene, an exception occurs as a result of the parent not being null.

      The bug was originally filed as JDK-8132898 but was closed because it was not reproducible. The problem with the test case was that it did not allow the SplitPane to do a layout pass first, you must add the control to the SplitPane, set the SplitPane on the scene allowing it to do a layout pass, and then attempt to remove the control and see that its parent is not null as it should be.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1) Create a SplitPane
      2) Create a Label or any other control
      3) Add the Label to the SplitPane
      4) Add the SplitPane to a scene and allow a layout pass to occur
      5) verify that after the layout pass, the parent of Label is correctly set to the SplitPane
      6) Remove the Label from the SplitPane
      7) The parent of the Label should be null, but it's not, even after another layout pass.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      After a control is removed from SplitPane, and the SplitPane has at least had the opportunity to perform a layout pass, the parent of the control removed should be null.
      ACTUAL -
      The parent of the removed control is not null even after another layout pass. This makes it impossible to add the removed control to a new scene.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Label@74ad73c0[styleClass=label]'test'is already inside a scene-graph and cannot be set as root
      at javafx.scene.Scene$9.invalidated(Scene.java:1100)
      at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:111)
      at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
      at javafx.scene.Scene.setRoot(Scene.java:1072)
      at javafx.scene.Scene.<init>(Scene.java:347)
      at javafx.scene.Scene.<init>(Scene.java:194)
      at test.SplitPaneDemo$1$1.run(SplitPaneDemo.java:36)
      at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
      at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
      at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
      at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
      at java.lang.Thread.run(Thread.java:745)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package test;

      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.control.SplitPane;
      import javafx.stage.Stage;

      public class SplitPaneDemo extends Application{
          
          @Override public void start(final Stage primaryStage) {
              final SplitPane split = new SplitPane();
              final Label label = new Label("test");
              split.getItems().add(label);
              System.out.println("The value is: " + label.getParent() +
                  " (just added, layout not performed, should be NULL)");

              Button button = new Button("Press Me");
              button.setOnAction(new EventHandler<ActionEvent> () {

                @Override
                public void handle(ActionEvent event) {
                  split.getItems().remove(label);
                  split.layout(); // seems to have no effect
                  split.requestLayout(); // seems to have no effect
                  Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                      System.out.println("The value is: " + label.getParent() + // reports SplitPaneSkin
                          " (button clicked, should be NULL?)");
                      
                      Scene scene = new Scene(label); // will fail because parent is not null so we are
                                                      // unable to move it to a new scene after removing
                                                      // nodes from a SplitPane
                      primaryStage.setScene(scene);
                    }
                  });
                }

              });
              split.getItems().add(button);

              primaryStage.setScene(new Scene(split));
              primaryStage.show();
          }
          
          public static void main(String[] args) {
              Application.launch(args);
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The only work around is to add the removed control to a BorderPane after removing it from SplitPane. Then removing it from BorderPane will properly set the parent to null. This solution is not ideal because you may not need the BorderPane.

      SUPPORT :
      YES

            jgiles Jonathan Giles
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: