Issue
Is there is a way to have the mouseevents getSceneX() and getSceneY() start from zero in a subScene?
I had the understanding (perhaps incorrect) that if you set a mouse events listener on a SubScene, the reported x,y coordinates would be based on that SubScene only (e.g. y=0 at top of SubScene, x=0 at left of SubScene).
What appears to happen in this example Application is that the reported x,y coordinates are based on the continuing scene and not the SubScene to which the listener is attached.
For this example, at the top of the SubScene, y reports as 46 rather than 0.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class SubsceneExample extends Application {
private final double sceneWidth = 600;
private final double sceneHeight = 600;
private double mousePosX;
private double mousePosY;
@Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
VBox controls = createControls();
root.getChildren().add(controls);
Pane scenePane = createPane();
SubScene subScene = new SubScene(scenePane, sceneWidth, sceneHeight);
subScene.setFill(Color.BLACK);
handleMouseEvents(subScene);
root.getChildren().add(subScene);
Scene scene = new Scene(root, sceneWidth, sceneHeight);
stage.setScene(scene);
stage.setTitle("Subscene Example");
stage.show();
}
private Pane createPane() {
Pane pane = new Pane();
pane.setPrefSize(sceneWidth, sceneHeight);
pane.setMaxSize(Pane.USE_COMPUTED_SIZE, Pane.USE_COMPUTED_SIZE);
pane.setMinSize(Pane.USE_COMPUTED_SIZE, Pane.USE_COMPUTED_SIZE);
pane.setBackground(Background.EMPTY);
return pane;
}
private VBox createControls() {
HBox hBox = new HBox(new Button("Button A"));
hBox.setAlignment(Pos.CENTER);
VBox controls = new VBox(10, hBox);
controls.setPadding(new Insets(10));
return controls;
}
private void handleMouseEvents(SubScene subScene) {
subScene.setOnMousePressed((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
System.out.printf("press:: x=%.2f, y=%.2f%n", mousePosX, mousePosY);
}
);
subScene.setOnMouseDragged((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
System.out.printf("drag:: x=%.2f, y=%.2f%n", mousePosX, mousePosY);
}
);
}
public static void main(String[] args) {
launch(args);
}
}
Solution
Ok, so I clarified that mouse events are always relative to the containing scene.
So for my example, I wanted the returned x,y for press, and drag events to be zero-ed for the subscene component.
I experimented and discovered that the easiest way was to get the bounds of the subscene "Bounds ofParent = subScene.getBoundsInParent();" and use this to offset the mouse position
Here is the answer:
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class SubsceneExample extends Application {
private final double sceneWidth = 600;
private final double sceneHeight = 600;
private double mousePosX;
private double mousePosY;
@Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
VBox controls = createControls();
root.getChildren().add(controls);
Pane scenePane = createPane();
SubScene subScene = new SubScene(scenePane, sceneWidth, sceneHeight);
subScene.setFill(Color.BLACK);
handleMouseEvents(subScene);
root.getChildren().add(subScene);
Scene scene = new Scene(root, sceneWidth, sceneHeight);
stage.setScene(scene);
stage.setTitle("Subscene Example");
stage.show();
}
private Pane createPane() {
Pane pane = new Pane();
pane.setPrefSize(sceneWidth, sceneHeight);
pane.setMaxSize(Pane.USE_COMPUTED_SIZE, Pane.USE_COMPUTED_SIZE);
pane.setMinSize(Pane.USE_COMPUTED_SIZE, Pane.USE_COMPUTED_SIZE);
pane.setBackground(Background.EMPTY);
return pane;
}
private VBox createControls() {
HBox hBox = new HBox(new Button("Button A"));
hBox.setAlignment(Pos.CENTER);
VBox controls = new VBox(10, hBox);
controls.setPadding(new Insets(10));
return controls;
}
private void handleMouseEvents(SubScene subScene) {
subScene.setOnMousePressed((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
Bounds ofParent = subScene.getBoundsInParent();
if (mousePosY >= ofParent.getMinY()) {
System.out.printf("press:: x=%.2f, y=%.2f%n", mousePosX - ofParent.getMinX(), mousePosY - ofParent.getMinY());
}
}
);
subScene.setOnMouseDragged((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
Bounds ofParent = subScene.getBoundsInParent();
if (mousePosY >= ofParent.getMinY()) {
System.out.printf("drag:: x=%.2f, y=%.2f%n", mousePosX - ofParent.getMinX(), mousePosY - ofParent.getMinY());
}
}
);
}
public static void main(String[] args) {
launch(args);
}
}
Answered By - EvilJinious1