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

Scene MouseHandler is referencing removed nodes

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • jfx17
    • jfx16
    • javafx
    • None

      The Scene$MouseHandler is holding on to a reference of nodes that have been removed from the Scene. This can cause issues when navigating through an application with the keyboard only (Nodes do not get garbage collected until a mouse click occurs).

      Run the below example, and follow it carefully:

      1) Click the *label* with the left mouse button
      2) Select the button with the keyboard (press space)

      Notice the the Button is removed from the Scene but is not being garbage collected. This is because Scene$MouseHandler pdrEventTargets field still contains a reference to the button, which is not being cleaned up because pdrInProgress is false when the removal code (which is supposed to do the clean up) runs.

      Sample code below:

          import java.lang.ref.WeakReference;
          
          import javafx.application.Application;
          import javafx.application.Platform;
          import javafx.scene.Scene;
          import javafx.scene.control.Button;
          import javafx.scene.control.Label;
          import javafx.scene.layout.HBox;
          import javafx.scene.layout.VBox;
          import javafx.stage.Stage;
          
          public class FrontEndRunner extends Application {
          
            public static void main(String[] args) {
              Application.launch(args);
            }
          
            @Override
            public void start(Stage stage) throws Exception {
              Button button = new Button("(2) Select me with keyboard");
              VBox box = new VBox(new HBox(button, new Label("(1) Click here first!")));
              WeakReference<Button> weakRef = new WeakReference<>(button);
          
              button.setOnAction(e -> {
                Label label = new Label("Thanks, button reference should disappear");
                box.getChildren().setAll(label);
          
                new Thread(() -> {
                  for(;;) {
                    try {
                      Thread.sleep(1000);
                      System.gc();
          
                      Platform.runLater(() -> {
                        label.setText("Button reference is: " + weakRef.get());
                      });
                    }
                    catch(InterruptedException e1) {
                      e1.printStackTrace();
                    }
                  }
                }).start();
              });
          
              button = null;
          
              Scene scene = new Scene(box);
          
              stage.setWidth(1000);
              stage.setScene(scene);
              stage.show();
            }
          }

            jhendrikx John Hendrikx
            jhendrikx John Hendrikx
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: