Cannot catch mouse events after having a certain transparency as a JavaFX Scene fill - javafx

I am trying to create an anchor pane that is transparent but you can drag it in the same time.
I set the stage transparent, I give the scene a transparent fill, and I set up the OnMousePressed etc on the pane.
The program behaves very strangely for me. There is a certain threshold for the transparency: if you are below this threshold, the pane will not catch mouse events. If above, then it will.
I give you an example. When I was writing this example, I found that the threshold here is between 0.5 and 0.6. It means: If I set the transparency of the fill to 0.5 or below the window will not be dragable, if to 0.6 or above, it will be.
My test code:
public class Main extends Application {
Stage primaryStage;
class Delta {
double x, y;
}
final Delta dragDelta = new Delta();
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
primaryStage.initStyle(StageStyle.TRANSPARENT);
showMain();
}
public void showMain() {
AnchorPane ap = new AnchorPane();
ap.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
dragDelta.x = primaryStage.getX() - mouseEvent.getScreenX();
dragDelta.y = primaryStage.getY() - mouseEvent.getScreenY();
}
});
ap.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
primaryStage.setX(mouseEvent.getScreenX() + dragDelta.x);
primaryStage.setY(mouseEvent.getScreenY() + dragDelta.y);
}
});
Scene scene = new Scene(ap);
scene.setFill(Color.rgb(252, 0, 4, 0.6));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String args[]) {
launch();
}
}
Can you explain or reproduce this behavior? Thank you!

This is not a bug - it's a feature. The general rule is that you cannot click on things which you cannot see. I'd prefer it if this decision would have been left to the programmer.

Related

Confusion on why an object wont draw a circle when trying to grab the window size

So, I have a pane being made in one class
#Override //Overridden nerd
public void start(Stage primaryStage) {
//makes a ball
Ball ball = new Ball();
//pause and resume animation
ball.setOnMousePressed(e -> ball.pause());
ball.setOnMouseReleased(e -> ball.play());
//increase/decrease speed
ball.setOnKeyPressed(e-> {
if(e.getCode() == KeyCode.UP) {
ball.increaseSpeed();
}
else if (e.getCode() == KeyCode.DOWN) {
ball.decreaseSpeed();
}
});
//creating a scene and setting its background
Scene scene = new Scene(ball, 500, 500);
primaryStage.setTitle("Random Walker");
primaryStage.setScene(scene);
primaryStage.show();
ball.requestFocus();
}
public static void main(String[] args) {
Application.launch(args);
}
}
and im trying to get the animation to start the ball at the center off the pane, and then bounce off the walls (im not on the bouncing part yet so I know that isnt perfect yet but im trying)
My problem is that when I try to get the ball to draw off of the current size of the window its not drawing anything at all, but will work if I manually put in the default screen size. any insight would be great, as I've been struggling with trying to finding any way to do this for a while, thanks.
public class setup extends Application {
#Override //Overridden nerd
public void start(Stage primaryStage) {
//makes a ball
Ball ball = new Ball();
//pause and resume animation
ball.setOnMousePressed(e -> ball.pause());
ball.setOnMouseReleased(e -> ball.play());
//increase/decrease speed
ball.setOnKeyPressed(e-> {
if(e.getCode() == KeyCode.UP) {
ball.increaseSpeed();
}
else if (e.getCode() == KeyCode.DOWN) {
ball.decreaseSpeed();
}
});
//creating a scene and setting its background
Scene scene = new Scene(ball, 500, 500);
primaryStage.setTitle("Random Walker");
primaryStage.setScene(scene);
primaryStage.show();
ball.requestFocus();
}
public static void main(String[] args) {
Application.launch(args);
}
}

JavaFX button unselect

I'm trying to make a sprite editor using JavaFX using buttons as the pixels. I am able to change the colour of each button on press, but I'm trying to get it so if I click and drag I can paint multiple pixels.
The problem I'm finding is that after clicking and holding onto a button, I am unable to select the new button when I move the mouse over new button to select that one too. If I click and drag re-entering that button I can get the "Paint Dragged Pixel" debug message, but not if I enter a new pixel with the mouse down, which is what I want. Also I can get the pixel button to print "Entered Pixel" when the mouse enters any button, but not for when I click and drag to a new pixel.
I think the problem is that when I click on one pixel I am locked in, and unable to select a new pixel by hovering over a new one. Is there a way to unbind this selection, or is the problem a different one.
Main Application:
public class Main extends Application {
boolean mousePressed = false;
public boolean isMousePressed() {
return mousePressed;
}
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane borderPane = new BorderPane();
primaryStage.setTitle("SpriteSheet");
Group root = new Group();
Scene scene = new Scene(borderPane, 500,200);
scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GridPane gridPane = new GridPane();
borderPane.setCenter(root);
for(int x = 0; x < 10; x++)
{
for(int y = 0; y < 10; y++) {
PixelButton button = new PixelButton();
button.setParentMain(this);
button.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mousePressed = true;
System.out.println("mouseDown");
}
});
button.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mousePressed = false;
System.out.println("mouseUp");
}
});
gridPane.add(button, x, y);
}
}
root.getChildren().add(gridPane);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The class for the PixelButton.
public class PixelButton extends Button {
Main parentMain;
public void setParentMain(Main parent) {
parentMain = parent;
}
public PixelButton() {
this.setMinSize(10, 10);
this.setPrefSize(10, 10);
this.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
}
});
this.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Entered Pixel");
if(parentMain.isMousePressed()){
System.out.println("Paint Dragged Pixel");
}
}
});
}
}
Thank you in advance.
Ok so I have been thinking about this one for a bit and have finally come up with a solution I simplified my solution a bit and used rectangles instead of buttons but you can transfer most of the code to the buttons as well so to start with this is not the exact functionality you were looking for but as close as I could get basically I fire an event on mouse press that releases the mouse click and as long as that event is not coming from the rectangle then dont flip the painting boolean paint and so you basically click to enter a "Paint Mode" and click again to get out of coloring tiles
public class Main extends Application {
private boolean mousePressed;
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane borderPane = new BorderPane();
primaryStage.setTitle("SpriteSheet");
Group root = new Group();
Scene scene = new Scene(borderPane, 500,200);
// scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GridPane gridPane = new GridPane();
borderPane.setCenter(root);
for(int x = 0; x < 10; x++) {
for(int y = 0; y < 10; y++) {
Rectangle rectangle = new Rectangle(10, 10);
rectangle.setOnMousePressed(event -> {
mousePressed = true;
System.out.println("mouseDown");
rectangle.fireEvent(new MouseEvent(MouseEvent.MOUSE_RELEASED,
rectangle.getLayoutX(), rectangle.getLayoutY(), rectangle.getLayoutX(), rectangle.getLayoutY(),
MouseButton.PRIMARY, 1,
false, false, false, false,
false, false, false, false,
false, false, null));
});
rectangle.setOnMouseReleased(event -> {
System.out.println(event.getSource());
if(!event.getSource().toString().equals("Rectangle[x=0.0, y=0.0, width=10.0, height=10.0, fill=0x000000ff]")) {
mousePressed = false;
System.out.println("mouseUp");
}
});
rectangle.setOnMouseMoved(event -> {
if(mousePressed) {
rectangle.setFill(Color.BLUE);
}
});
gridPane.add(rectangle, x, y);
}
}
root.getChildren().add(gridPane);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}

Fitting rotated ImageView into Application Window / Scene

In JavaFX I am trying to show an rotated ImageView in an Application Window.
Therefore I have put it into a stackPane to have it always centered and I have bound the widths/heights of the ImageView and the stackPane to the scene's width/height to view it just as large as possible.
This works fine as soon as the Image is not rotated.
As soon as I rotate the Image by 90° using stackPane.setRotate(90) (and exchange binding for width/height) then the stackPane is no longer bound to the upper left corner of the Application Window (or scene).
What can I do to place the rotated image correctly?
In the example code [any key] will toggle the rotation 90°/0° so the location problem of the rotated image becomes visible:
public class RotationTest extends Application {
boolean rotated = false;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Rotation test");
Group root = new Group();
Scene scene = new Scene(root, 1024,768);
//a stackPane is used to center the image
StackPane stackPane = new StackPane();
stackPane.setStyle("-fx-background-color: black;");
stackPane.prefHeightProperty().bind(scene.heightProperty());
stackPane.prefWidthProperty().bind(scene.widthProperty());
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
//toggle rotate 90° / no rotation
rotated = !rotated;
stackPane.prefHeightProperty().unbind();
stackPane.prefWidthProperty().unbind();
if (rotated){
stackPane.setRotate(90);
//rotation: exchange width and height for binding to scene
stackPane.prefWidthProperty().bind(scene.heightProperty());
stackPane.prefHeightProperty().bind(scene.widthProperty());
}else{
stackPane.setRotate(0);
//no rotation: height is height and width is width
stackPane.prefHeightProperty().bind(scene.heightProperty());
stackPane.prefWidthProperty().bind(scene.widthProperty());
}
}
});
final ImageView imageView = new ImageView("file:D:/test.jpg");
imageView.setPreserveRatio(true);
imageView.fitWidthProperty().bind(stackPane.prefWidthProperty());
imageView.fitHeightProperty().bind(stackPane.prefHeightProperty());
stackPane.getChildren().add(imageView);
root.getChildren().add(stackPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Results:
Without rotation the stackPane (black) fits the window perfectly and the image has the correct size even if the window is resized with the mouse.
After pressing [any key] the stackPane is rotated. The stackPane (black) seems to have the correct width/height and also the image seems to be correctly rotated. But the stackPane is no longer in the upper left corner??? It moves around when the window is resized with the mouse???
Why not simply leave the Group and the preferred sizes out of the equation?
The root is automatically resized to fit the scene and you can use it's width/height properties to bind the fitWidth and fitHeight properties:
private static void setRotated(boolean rotated, ImageView targetNode, Pane parent) {
double angle;
if (rotated) {
angle = 90;
targetNode.fitWidthProperty().bind(parent.heightProperty());
targetNode.fitHeightProperty().bind(parent.widthProperty());
} else {
angle = 0;
targetNode.fitWidthProperty().bind(parent.widthProperty());
targetNode.fitHeightProperty().bind(parent.heightProperty());
}
targetNode.setRotate(angle);
}
#Override
public void start(Stage primaryStage) {
Image image = new Image("file:D:/test.jpg");
ImageView imageView = new ImageView(image);
imageView.setPreserveRatio(true);
StackPane root = new StackPane(imageView);
root.setStyle("-fx-background-color: black;");
// initialize unrotated
setRotated(false, imageView, root);
Scene scene = new Scene(root, 1024, 768);
scene.setOnKeyPressed(evt -> {
// toggle between 0° and 90° rotation
setRotated(imageView.getRotate() == 0, imageView, root);
});
primaryStage.setScene(scene);
primaryStage.show();
}
Note that this may not result in correct layout, if placed in some other layout, since the size constraints may be calculated wrong.
You could implement your own region though to fix this:
public class CenteredImage extends Region {
private final BooleanProperty rotated = new SimpleBooleanProperty();
private final ImageView imageView = new ImageView();
public CenteredImage() {
// make sure layout gets invalidated when the image changes
InvalidationListener listener = o -> requestLayout();
imageProperty().addListener(listener);
rotated.addListener((o, oldValue, newValue) -> {
imageView.setRotate(newValue ? 90 : 0);
requestLayout();
});
getChildren().add(imageView);
imageView.setPreserveRatio(true);
}
public final BooleanProperty rotatedProperty() {
return rotated;
}
public final void setRotated(boolean value) {
this.rotated.set(value);
}
public boolean isRotated() {
return rotated.get();
}
public final void setImage(Image value) {
imageView.setImage(value);
}
public final Image getImage() {
return imageView.getImage();
}
public final ObjectProperty<Image> imageProperty() {
return imageView.imageProperty();
}
#Override
protected double computeMinWidth(double height) {
return 0;
}
#Override
protected double computeMinHeight(double width) {
return 0;
}
#Override
protected double computePrefWidth(double height) {
Image image = getImage();
Insets insets = getInsets();
double add = 0;
if (image != null && height > 0) {
height -= insets.getBottom() + insets.getTop();
add = isRotated()
? height / image.getWidth() * image.getHeight()
: height / image.getHeight() * image.getWidth();
}
return insets.getLeft() + insets.getRight() + add;
}
#Override
protected double computePrefHeight(double width) {
Image image = getImage();
Insets insets = getInsets();
double add = 0;
if (image != null && width > 0) {
width -= insets.getLeft() + insets.getRight();
add = isRotated()
? width / image.getHeight() * image.getWidth()
: width / image.getWidth() * image.getHeight();
}
return insets.getTop() + insets.getBottom() + add;
}
#Override
protected double computeMaxWidth(double height) {
return Double.MAX_VALUE;
}
#Override
protected double computeMaxHeight(double width) {
return Double.MAX_VALUE;
}
#Override
protected void layoutChildren() {
Insets insets = getInsets();
double left = insets.getLeft();
double top = insets.getTop();
double availableWidth = getWidth() - left - insets.getRight();
double availableHeight = getHeight() - top - insets.getBottom();
// set fit sizes
if (isRotated()) {
imageView.setFitWidth(availableHeight);
imageView.setFitHeight(availableWidth);
} else {
imageView.setFitWidth(availableWidth);
imageView.setFitHeight(availableHeight);
}
// place image
layoutInArea(imageView, left, top, availableWidth, availableHeight, 0, null, false,
false, HPos.CENTER, VPos.CENTER);
}
}
#Override
public void start(Stage primaryStage) {
Image image = new Image("file:D:/test.jpg");
ImageView imageView = new ImageView(image);
imageView.setPreserveRatio(true);
CenteredImage imageArea = new CenteredImage();
imageArea.setImage(image);
imageArea.setStyle("-fx-background-color: black;");
imageArea.setPrefWidth(300);
SplitPane splitPane = new SplitPane(new Region(), imageArea);
SplitPane.setResizableWithParent(imageArea, true);
Scene scene = new Scene(splitPane, 1024, 768);
scene.setOnKeyPressed(evt -> {
// toggle between 0° and 90° rotation
imageArea.setRotated(!imageArea.isRotated());
});
primaryStage.setScene(scene);
primaryStage.show();
}
I found a solution :-) Fabian's approach inspired me (thank you!!) And my old friend Pit helped me with debugging (also thank you!!)
It seems that the layout location algorithm of JavaFX has a problem when resize() is applied to rotated Panes (or even Nodes - I have not tried):
Following Fabian's idea I debugged into the layoutChildren() method of class Pane. I found that the relocation after setRotate() is correct and keeps the center of the child pane as expected. But as soon as resize() is called (which is done because of fitting the rotated child pane again into its father and additionally always when the window is resized by the user) the origin calculation goes wrong:
The picture above depicts a sequence of setRotate(90), resize() and relocate() in green and the same for setRotate(270) in blue. A little blue/green circle depicts the corresponding origin together with its coordinates in the 1024x786 example.
Analysis
It seems that for calculation the position of the Pane resize() does not use the height and width from BoundsInParent-Property (see JavaFX-Docu of Node) but from getWidth() and getHeight() which seem to reflect BoundsInLocal. As a consequence, for rotations of 90° or 270° height and width seem to be interchanged. Therefore the error in the calculation for the new origin is just the half of the difference between width and height (delta=(width-height)/2) when resize() tries to center the child pane again after the resizing.
Solution
A relocation(delta,-delta) needs to be applied after resizing for Panes with rotation=90 or 270 degrees.
The structure of my implementation follows Fabian's basic idea: I have build a layouter RotatablePaneLayouter:Region that just overwrites the layoutChildren() method. In its constructor it gets a Pane (in my example a StackPane) which can contain any number of children (in my example an ImageView) and that can be rotated.
LayoutChildren() then just executes resize() and relocate() for the child pane to fit it completely into the RotateablePaneLayouter respecting the orientation of the child pane.
The Layouter Helper (RotateablePaneLayouter:Region)
public class RotatablePaneLayouter extends Region {
private Pane child;
public RotatablePaneLayouter(Pane child) {
getChildren().add(child);
this.child = child;
// make sure layout gets invalidated when the child orientation changes
child.rotateProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
requestLayout();
}
});
}
#Override
protected void layoutChildren() {
// set fit sizes:
//resize child to fit into RotatablePane and correct movement caused by resizing if necessary
if ((child.getRotate() == 90)||(child.getRotate() == 270)) {
//vertical
child.resize( getHeight(), getWidth() ); //exchange width and height
// and relocate to correct movement caused by resizing
double delta = (getWidth() - getHeight()) / 2;
child.relocate(delta,-delta);
} else {
//horizontal
child.resize( getWidth(), getHeight() ); //keep width and height
//with 0° or 180° resize does no movement to be corrected
child.relocate(0,0);
}
}
}
To use it: Place the Pane to be rotated into the Layouter first instead of placing the Pane directly.
Here the code for the example's main program. You can use the space bar to rotate the child pane by 90, 180, 270 and again 0 degrees. You can also resize the window with the mouse. The layouter always manages to place the rotated pane correctly.
Expample for using the Layouter
public class RotationTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
//image in a StackPane to be rotated
final ImageView imageView = new ImageView("file:D:/Test_org.jpg");
imageView.setPreserveRatio(true);
StackPane stackPane = new StackPane(imageView); //a stackPane is used to center the image
stackPane.setStyle("-fx-background-color: black;");
imageView.fitWidthProperty().bind(stackPane.widthProperty());
imageView.fitHeightProperty().bind(stackPane.heightProperty());
//container for layouting rotated Panes
RotatablePaneLayouter root = new RotatablePaneLayouter(stackPane);
root.setStyle("-fx-background-color: blue;");
Scene scene = new Scene(root, 1024,768);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.SPACE) {
//rotate additionally 90°
stackPane.setRotate((stackPane.getRotate() + 90) % 360);
}
}
});
primaryStage.setTitle("Rotation test");
primaryStage.setScene(scene);
primaryStage.show();
}
}
For me this seems like a workaround of a javaFX bug in resize().

JavaFX:how to resize the stage when using webview

for example:
public class WebViewTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final WebView view = new WebView();
final WebEngine webEngine = view.getEngine();
Scene scene = new Scene(view, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
Platform.runLater(() -> {
webEngine.getLoadWorker().progressProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (newValue.doubleValue() == 1D) {
String heightText = webEngine.executeScript(
"window.getComputedStyle(document.body, null).getPropertyValue('height')"
).toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript(
"window.getComputedStyle(document.body, null).getPropertyValue('width')"
).toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
primaryStage.setWidth(width);
primaryStage.setHeight(height);
}
}
});
webEngine.load("http://www.baidu.com/");
});
}
public static void main(String[] args) {
launch(args);
}
}
I want to resize the primaryStage after loading. But finally, I get the size is 586*586, and the primaryStage shows like this:
enter image description here
Actually, I don't want the rolling style, so how can I remove the scroll bar? If I use primaryStage.setWidth() or primaryStage.setHeight() to set the size of primaryStage very big at the beginning, the scroll bar will not exist. But that not I need, I want to resize the size dynamically, because the url will change.
This is similar to the solution given by RKJ (relies on querying WebView for the document width and height).
This solution adds a couple of things:
Ability to completely remove WebView scroll bars at all times (you may or may not want this as it stops the user being able to scroll large documents or view complete documents if the user manually makes the window smaller).
A call to stage.sizeToScene() to size the stage precisely to the scene size.
The behavior of this solution is kind of weird due to some implementation details of WebView. WebView does not load the document unless it is displayed on the stage, so you can't know the document size until you try to display it. So you need to display the document, then resize the stage to fit the document, which results in a delay after the stage has been initially shown and when it resizes to exactly fit the document. This provides, for certain documents, a visible jump in the stage size which just looks weird. Also documents larger than the screen size (which are common on the web) cannot be displayed in full as the stage can only maximally resize to fill the available screen real estate and without any scroll bars you can't see part of the document. So in all, I don't think this solution is really useful.
no-overflow.css
body {
overflow-x: hidden;
overflow-y: hidden;
}
WebViewTest.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewTest extends Application {
#Override
public void start(Stage stage) throws Exception {
final WebView view = new WebView();
view.getEngine().setUserStyleSheetLocation(
getClass().getResource("no-overflow.css").toExternalForm()
);
final WebEngine webEngine = view.getEngine();
webEngine.getLoadWorker().runningProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Running: " + newValue);
if (!newValue) {
String heightText = webEngine.executeScript(
"document.height"
).toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript(
"document.width"
).toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
view.setMinSize(width, height);
view.setPrefSize(width, height);
view.setMaxSize(width, height);
stage.sizeToScene();
System.out.println(view.getLayoutBounds());
}
});
webEngine.load("http://www.baidu.com");
Scene scene = new Scene(view);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
public class WebViewTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final WebView view = new WebView();
final WebEngine webEngine = view.getEngine();
Scene scene = new Scene(view, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
Platform.runLater(() -> {
webEngine.getLoadWorker().progressProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (newValue.doubleValue() == 1D) {
String heightText = webEngine.executeScript("document.height").toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript("document.width").toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
primaryStage.setWidth(width+50);
primaryStage.setHeight(height+50);
primaryStage.hide();
primaryStage.show();
}
}
});
webEngine.load("http://baidu.com/");
});
}
public static void main(String[] args) {
launch(args);
}
}
use document.height and document.width to get the actual dimension, there is slight difference between the pixel size and stage size measurement so, I added 50 pixel extra and hide the stage and show it again but it is more better if you use WebView inside StackPane Container.
rkjoshi

How to write a MouseListener for JavaFX

I want to write a little game where I shoot from an object to a specific direction on a JavaFX Panel using my mouse position.
I want to turn a Line in the direction where my Mouse is.
Line line = new Line(startPosX, startPosY, mouseDirectionX, mouseDirectionY);
How can I do that?
Add a MOUSE_MOVED event filter like this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Line line = new Line( 400,200,400,200);
root.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
line.setEndX(e.getSceneX());
line.setEndY(e.getSceneY());
});
root.getChildren().add(line);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you want the line to be limited in length, you'll have to do the proper calculations of course via the angle.

Resources