-
Enhancement
-
Resolution: Fixed
-
P4
-
7u25, 8
Following test programm illustrates the issue:
========================
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.DragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
/**
* In this test app, an ellipse is moved like a cursor at the mouse position. The ellipses position is updated by
* a MouseEvent handler listening for the MouseEvent.MOUSE_MOVED and MouseEvent.MOUSE_DRAGGED.
* A problem occurs when the child node on which the drag started (another ellipse in this example) is removed from
* the stage during the drag gesture. In this case, no further MOUSE_DRAGGED events are reported.
*/
public class MouseEventTest extends Application {
private Stage primaryStage;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) {
this.primaryStage = primaryStage;
Scene scene = new Scene(createPane(), 600, 600);
primaryStage.setTitle("MouseEvent Test App");
primaryStage.setScene(scene);
primaryStage.show();
}
private Parent createPane() {
final Group contentGroup = new Group();
// the cursor that is updated on mouse move and mouse drag
final Ellipse cursor = new Ellipse(0, 0, 10, 10);
cursor.setFill(Color.ORANGE);
cursor.setMouseTransparent(true);
contentGroup.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
if (MouseEvent.MOUSE_MOVED.equals(mouseEvent.getEventType())
|| MouseEvent.MOUSE_DRAGGED.equals(mouseEvent.getEventType())) {
cursor.setLayoutX(mouseEvent.getX());
cursor.setLayoutY(mouseEvent.getY());
}
}
});
// a background
contentGroup.getChildren().add(new Rectangle(600, 600, Color.BLUE));
// a child that gets removed later
contentGroup.getChildren().add(createChild());
// the cursor
contentGroup.getChildren().add(cursor);
return contentGroup;
}
// creates an ellipse that removes itself from its parent on MouseEvent.DRAG_DETECTED and replaces itself by another
// ellipse
private Node createChild() {
final Ellipse ellipse = new Ellipse(300, 300, 200, 200);
ellipse.addEventHandler(MouseEvent.DRAG_DETECTED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
Group parent = (Group) ellipse.getParent();
parent.getChildren().remove(ellipse);
parent.getChildren().add(1, createChild());
// none of this approaches work; no one receives mouse / drag events anymore!
// window
primaryStage.getScene().getWindow().addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.getScene().getWindow().addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
// stage
primaryStage.getScene().addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.getScene().addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
// scene
primaryStage.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
}
});
return ellipse;
}
}
====================
after the node is removed while dragging, no mouse events reach the scene anymore until the mouse is released. DragEvents still reach the removed node which is actually good because by this we can compensate the former issue.
========================
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.DragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
/**
* In this test app, an ellipse is moved like a cursor at the mouse position. The ellipses position is updated by
* a MouseEvent handler listening for the MouseEvent.MOUSE_MOVED and MouseEvent.MOUSE_DRAGGED.
* A problem occurs when the child node on which the drag started (another ellipse in this example) is removed from
* the stage during the drag gesture. In this case, no further MOUSE_DRAGGED events are reported.
*/
public class MouseEventTest extends Application {
private Stage primaryStage;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) {
this.primaryStage = primaryStage;
Scene scene = new Scene(createPane(), 600, 600);
primaryStage.setTitle("MouseEvent Test App");
primaryStage.setScene(scene);
primaryStage.show();
}
private Parent createPane() {
final Group contentGroup = new Group();
// the cursor that is updated on mouse move and mouse drag
final Ellipse cursor = new Ellipse(0, 0, 10, 10);
cursor.setFill(Color.ORANGE);
cursor.setMouseTransparent(true);
contentGroup.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
if (MouseEvent.MOUSE_MOVED.equals(mouseEvent.getEventType())
|| MouseEvent.MOUSE_DRAGGED.equals(mouseEvent.getEventType())) {
cursor.setLayoutX(mouseEvent.getX());
cursor.setLayoutY(mouseEvent.getY());
}
}
});
// a background
contentGroup.getChildren().add(new Rectangle(600, 600, Color.BLUE));
// a child that gets removed later
contentGroup.getChildren().add(createChild());
// the cursor
contentGroup.getChildren().add(cursor);
return contentGroup;
}
// creates an ellipse that removes itself from its parent on MouseEvent.DRAG_DETECTED and replaces itself by another
// ellipse
private Node createChild() {
final Ellipse ellipse = new Ellipse(300, 300, 200, 200);
ellipse.addEventHandler(MouseEvent.DRAG_DETECTED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
Group parent = (Group) ellipse.getParent();
parent.getChildren().remove(ellipse);
parent.getChildren().add(1, createChild());
// none of this approaches work; no one receives mouse / drag events anymore!
// window
primaryStage.getScene().getWindow().addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.getScene().getWindow().addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
// stage
primaryStage.getScene().addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.getScene().addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
// scene
primaryStage.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent);
}
});
primaryStage.addEventFilter(DragEvent.ANY, new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println(dragEvent);
}
});
}
});
return ellipse;
}
}
====================
after the node is removed while dragging, no mouse events reach the scene anymore until the mouse is released. DragEvents still reach the removed node which is actually good because by this we can compensate the former issue.