i have a draggable container in JavaFX. This Container is implemented in a PopUp. I can drag the Container, but if i drag it, the mouse-event hasn't a constant coordinate. There switchs the mouse position very fast between 2 fix Positions.
Thats my code:
container.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
// TODO Auto-generated method stub
if(dragAct==true){
//Set the Position of the PopUp to the Position of the Mouse
setX(me.getX());
setY(me.getY());
}
}
});
The containe is a VBox. The Main-Class is a extended Version of the PopUp-Class.
JavaFX Container Draggable
The setX and setY methods you call set the position of the Popup in screen coordinates. The calls to me.getX() and me.getY() give you the coordinates of the mouse relative to the container. When you move the popup, the container also moves, so the position of the mouse has changed relative to the container. So your calculations are not going to be consistent from one dragging event to the next.
The fix is to compute the positions relative to something that is fixed. Since you are moving the popup, which is a window, the fixed coordinate system is the screen coordinate system. MouseEvent has getScreenX and getScreenY methods you can use to easily get these.
I like to implement dragging by saving the last mouse location and then computing the distance moved on drag. There are other (possibly less verbose) ways to do this but to me this is clearest:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class DraggingPopup extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Show popup");
button.setOnAction(event -> showDraggablePopup(primaryStage));
StackPane root = new StackPane(button);
Scene scene = new Scene(root, 250, 75);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showDraggablePopup(Stage owner) {
Popup popup = new Popup();
Button closeButton = new Button("Close");
closeButton.setOnAction(event -> popup.hide());
StackPane container = new StackPane(closeButton);
container.setStyle("-fx-background-color: steelblue;");
container.setMinWidth(300);
container.setMinHeight(125);
// Dragging implementation:
ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<>();
container.setOnMousePressed(event ->
mouseLocation.set(new Point2D(event.getScreenX(), event.getScreenY())));
container.setOnMouseDragged(event -> {
if (mouseLocation.get() != null) {
double x = event.getScreenX();
double deltaX = x - mouseLocation.get().getX() ;
double y = event.getScreenY();
double deltaY = y - mouseLocation.get().getY() ;
//in case of 2 or more computer screens this help me to avoid get stuck on 1 screen
if(Math.abs(popup.getX()-x)>popup.getWidth()){
popup.setX(x);
popup.setY(y);
}else {
popup.setX(popup.getX() + deltaX);
popup.setY(popup.getY() + deltaY);
}
mouseLocation.set(new Point2D(x, y));
}
});
container.setOnMouseReleased(event -> mouseLocation.set(null));
popup.getScene().setRoot(container);
popup.show(owner);
}
public static void main(String[] args) {
launch(args);
}
}
Related
I've managed to move the camera using mouse drag. However, the problem is that once I've moved the camera and released the mouse press, the camera returns back to the origin.
I want the camera to remain in the changed position instead so that when I use the mouse again to move the camera, it moves from that position to wherever instead of from the origin.
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Sphere;
public class Main extends Application {
private static final int WIDTH = 900;
private static final int HEIGHT = 600;
//Tracks drag starting point for x and y
private double anchorX, anchorY;
#Override
public void start(Stage primaryStage) {
Sphere sphere = new Sphere(50);
Group group = new Group();
group.getChildren().add(sphere);
Camera camera = new PerspectiveCamera();
Scene scene = new Scene(group, WIDTH, HEIGHT);
scene.setFill(Color.SILVER);
scene.setCamera(camera);
sphere.setTranslateX(WIDTH / 2);
sphere.setTranslateY(HEIGHT / 2);
initMouseControl(scene, camera, primaryStage, sphere);
primaryStage.setTitle("Solar System Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
private void initMouseControl(Scene scene, Camera camera, Stage stage, Sphere sphere) {
scene.setOnMousePressed(event -> {
//Save start points
anchorX = event.getSceneX();
anchorY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
camera.setTranslateY(anchorY - event.getSceneY());
camera.setTranslateX(anchorX - event.getSceneX());
});
stage.addEventHandler(ScrollEvent.SCROLL, event -> {
sphere.setTranslateZ(sphere.getTranslateZ() + event.getDeltaY());
});
}
public static void main(String[] args) {
launch(args);
}
}
I've tried googling to find a solution but couldn't find much on camera movement with javafx
First of all, your scene does not have depth buffer enabled . These constructors enable 3d features in a scene instance Scene(Parent root,double width,double height,boolean depthBuffer) and Scene(Parent root,double width,double height,boolean depthBuffer,SceneAntialiasing antiAliasing) both with depthBufer boolean set to true. Second ,if you want to translate a node ; translate it getting its current coordinates and then add new coords . that will avoid reset coords . I divided the dragged result by 10 because it brought too high values
public class Main extends Application {
private static final int WIDTH = 900;
private static final int HEIGHT = 600;
//Tracks drag starting point for x and y
private double anchorX, anchorY;
#Override
public void start(Stage primaryStage) {
Sphere sphere = new Sphere(50);
Group group = new Group();
group.getChildren().add(sphere);
Camera camera = new PerspectiveCamera();
// for 3d Scene constructor must have zbuffer= true and SceneAntialiasing
Scene scene = new Scene(group, WIDTH, HEIGHT, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.SILVER);
scene.setCamera(camera);
sphere.setTranslateX(WIDTH / 2);
sphere.setTranslateY(HEIGHT / 2);
initMouseControl(scene, camera, primaryStage, sphere);
primaryStage.setTitle("Solar System Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
private void initMouseControl(Scene scene, Camera camera, Stage stage, Sphere sphere) {
scene.setOnMousePressed(event -> {
//Save start points
anchorX = event.getSceneX();
anchorY = event.getSceneY();
});
// translating camera from its current coords pluss event
scene.setOnMouseDragged(event -> {
camera.setTranslateY(camera.getTranslateY() + ((anchorY - event.getSceneY()) / 10));
camera.setTranslateX(camera.getTranslateX() + ((anchorX - event.getSceneX()) / 10));
});
stage.addEventHandler(ScrollEvent.SCROLL, event -> {
sphere.setTranslateZ(sphere.getTranslateZ() + event.getDeltaY());
});
}
public static void main(String[] args) {
launch(args);
}
}
I don't know in how far Google can help you fix your logic problems. I did no further analysis of your code but at least each time when you press the mouse button your camera position is reset to zero by design. Your changes are not cumulative.
My task is to write a program that makes a circle ball that gradually fades away as the ball moves to the right. But it's not working, I can make the ball move when the mouse is dragged but the opacity is the same. Can you guys help me? I don't know how to convert the opacity value into double
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
public class Project3 extends Application
{
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
Pane root = createRootPane();
Scene scene1 = new Scene(root);
primaryStage.setScene(scene1);
primaryStage.setTitle(" Hai Vo ");
primaryStage.show();
}
public Pane createRootPane()
{
Circle ball = new Circle (100,50,25);
Pane root = new Pane(ball);
root.setMinSize(300,300);
root.setOnMouseDragged (
event ->
{
double x = event.getX();
ball.setCenterX(event.getX());
ball.setCenterY(event.getY());
ball.opacityProperty().bind(ball.centerXProperty());
double opacity = ball.opacityProperty();
ball.setOpacity(opacity);
} );
return root;
}
}
First, move the binding out of the event handler. The binding will ensure the opacity is always updated when the centerX property updates.
Second, don't set bound values; the last two lines of the event handler just set the opacity to its current value anyway.
Third, the opacity should be between 0 and 1. You want it to be 1 when centerX is 0 and 0 when centerX is 300 (or, generally, the width of the pane).
What you need is (in pseudocode)
opacity = 1 - ball.centerX / root.width
= (ball.centerX / root.width) * (-1) + 1
which you can express in bindings with
ball.centerXProperty()
.divide(root.widthProperty())
.multiply(-1)
.add(1)
So put together, you need:
public Pane createRootPane() {
Circle ball = new Circle (100,50,25);
Pane root = new Pane(ball);
ball.opacityProperty().bind(
ball.centerXProperty()
.divide(root.widthProperty())
.multiply(-1)
.add(1)
);
root.setMinSize(300,300);
root.setOnMouseDragged (
event ->
{
ball.setCenterX(event.getX());
ball.setCenterY(event.getY());
} );
return root;
}
I want my blue circle go from one light blue circle to another, but only does half.
The coordinates appear being the same:
initial_lightblue: 211.7,230.5
blue: 193.7,239.1
final_lighblue: 193.7,239.1
My code
TranslateTransition transition = new TranslateTransition();
transition.setToX(c.getX());
transition.setToY(c.getY());
transition.setNode(view);
transition.setInterpolator(Interpolator.LINEAR);
transition.play();
Any sugestions?
From documentation
TranslateTransition : This Transition creates a move/translate animation that spans its duration. This is done by updating the
translateX, translateY and translateZ variables of the node at regular
interval.
So it's going to use the translate properties in order to relocate the actual node inside your pane. With that being said if you locate your node at x=50 and y=50 by setting its layoutX and layoutY properties their translation values will be 0, so if you actually try to set the end coordinates of the TranslateTransition to be ex. x = 100 y = 100 then its going to move your Node to the x = 150 and y = 150 and not to the (x,y) = (100,100) cause its going to change the translation property (x and y) from 0 to 100 which will move the node eventually to (x,y) = 150,150.
With that been said here is an example :
import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Test extends Application {
private Circle c1;
private Circle c2;
#Override
public void start(Stage stage) throws Exception {
AnchorPane pane = new AnchorPane();
// Set only the radius
c1 = new Circle(5);
c1.setFill(Color.BLUE);
// Let's translate the c1 to the location we want
c1.setTranslateX(50);
c1.setTranslateY(60);
// The same for circle2
c2 = new Circle(5);
c2.setFill(Color.RED);
c2.setTranslateX(120);
c2.setTranslateY(200);
pane.getChildren().addAll(c1, c2);
pane.setOnMouseClicked(e -> {
startAnimation();
});
stage.setScene(new Scene(pane, 400, 500));
stage.show();
}
private void startAnimation() {
TranslateTransition transition = new TranslateTransition();
transition.setNode(c1);
transition.setToX(c2.getTranslateX());
transition.setToY(c2.getTranslateY());
transition.setInterpolator(Interpolator.LINEAR);
transition.play();
}
public static void main(String[] args) {
launch(args);
}
}
P.S : In your code example you are referring to circles but you call c.getX() to actually take the x of the circle, that is quite strange cause the Circle class doesn't have method getX() I am quessing you are referreing to getCenterX() or those are not Circles .
I'm trying to drag nodes about and drop them onto each other. This is a simple class that I expected would react to drag gestures but it doesn't
public class CircleDrag extends Circle
{
double x, y;
String name;
int count = 0;
public CircleDrag(double centerX, double centerY, String name)
{
super(centerX, centerY, 10);
this.name = name;
setOnDragDetected(e ->
{
startFullDrag();
startDragAndDrop(TransferMode.ANY); // tried with and without this line.
logIt(e);
});
setOnDragEntered(e ->
{
logIt(e);
});
setOnDragDone(e ->
{
logIt(e);
});
setOnDragOver(e ->
{
logIt(e);
});
setOnMousePressed(e ->
{
logIt(e);
setMouseTransparent(true);
x = getLayoutX() - e.getSceneX();
y = getLayoutY() - e.getSceneY();
});
setOnMouseReleased(e ->
{
logIt(e);
setMouseTransparent(false);
});
setOnMouseDragged(e ->
{
logIt(e);
setLayoutX(e.getSceneX() + x);
setLayoutY(e.getSceneY() + y);
});
}
private void logIt(Event e)
{
System.out.printf("%05d %s: %s\n", count++, name, e.getEventType().getName());
}
}
I was expecting to add a bunch of CircleDrags to a pane and when dragging one onto another the other would fire an onDrag* event. But it doesn't.
What is it I don't understand about this gesture?
Thanks
Ollie.
Here's how you could do it in general:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class PhysicsTest extends Application {
public static List<Circle> circles = new ArrayList<Circle>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Circle circle1 = new Circle( 50);
circle1.setStroke(Color.GREEN);
circle1.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.3));
circle1.relocate(100, 100);
Circle circle2 = new Circle( 50);
circle2.setStroke(Color.BLUE);
circle2.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.3));
circle2.relocate(200, 200);
MouseGestures mg = new MouseGestures();
mg.makeDraggable( circle1);
mg.makeDraggable( circle2);
circles.add( circle1);
circles.add( circle2);
root.getChildren().addAll(circle1, circle2);
primaryStage.setScene(new Scene(root, 1600, 900));
primaryStage.show();
}
public static class MouseGestures {
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
public void makeDraggable( Node node) {
node.setOnMousePressed(circleOnMousePressedEventHandler);
node.setOnMouseDragged(circleOnMouseDraggedEventHandler);
}
EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
Circle p = ((Circle) (t.getSource()));
orgTranslateX = p.getCenterX();
orgTranslateY = p.getCenterY();
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
Circle p = ((Circle) (t.getSource()));
p.setCenterX(newTranslateX);
p.setCenterY(newTranslateY);
for( Circle c: circles) {
if( c == p)
continue;
if( c.getBoundsInParent().intersects(p.getBoundsInParent())) {
System.out.println( "Overlapping!");
}
}
}
};
}
}
Please note that this solution uses the bounds in the parent, ie in the end a rectangle is used for overlap check. If you want to use eg a circle check, you could use the radius and check the distance between the circles. Depends on your requirement.
Challenges with your current solution
You need to put some content in the dragboard
If you don't put anything in the dragboard when the drag is initially detected, there is nothing to drag, so subsequent drag related events such as dragEntered, dragDone and dragOver will never be fired.
Conflating both "dragging the node using a mouse" with "drag and drop content processing" is hard
I couldn't get it to work exactly as you have it with the drag handled by mouse drag events as well as having a drag and drop operation in effect because as soon as the drag and drop operation took effect, the node stopped receiving mouse drag events.
Sample Solution
As a result of the above challenges, the approach I took was:
Put something in the dragboard when a drag is detected.
Remove the mouse event handlers and only use drag event handlers.
Simulate dragging the node around by taking a snapshot of the node to an image, then hiding the node and making use of the DragView with the node image.
When the drag process completes, detect the current location of the mouse cursor then relocate the node to that location.
Unfortunately, JavaFX drag events are unlike mouse events. The drag events don't seem to include full location information (e.g. x,y or sceneX,sceneY). This means you need a way to determine this information independent of the event. I don't know of an API in JavaFX to detect the current location of the mouse cursor, so I had to resort to the awt MouseInfo class to determine the current mouse location.
In the process, I lost a little bit of the accuracy in initial and final node location calculation. For small circles, that doesn't not seem to matter. For other apps, you could probably modify my logic slightly to make the drag and drop transitions 100% accurate and smooth.
I used Java 8 for the sample solution (DragView is not available in Java 7). CircleDrag is an updated version of your draggable node with drag and drop handling. The CircleDragApp is just a JavaFX application test harness for the CircleDrag nodes.
CircleDrag.java
import javafx.event.Event;
import javafx.scene.SnapshotParameters;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import java.awt.Point;
import java.awt.MouseInfo;
public class CircleDrag extends Circle {
private final String name;
private int count = 0;
public CircleDrag(double centerX, double centerY, String name) {
super(centerX, centerY, 10);
this.name = name;
setOnDragDetected(e -> {
ClipboardContent content = new ClipboardContent();
content.putString(name);
Dragboard dragboard = startDragAndDrop(TransferMode.ANY);
dragboard.setContent(content);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
dragboard.setDragView(snapshot(params, null));
dragboard.setDragViewOffsetX(dragboard.getDragView().getWidth() / 2);
dragboard.setDragViewOffsetY(dragboard.getDragView().getHeight() / 2);
setVisible(false);
e.consume();
logIt(e);
});
setOnDragEntered(this::logIt);
setOnDragDone(e ->
{
Point p = MouseInfo.getPointerInfo().getLocation();
relocate(
p.x - getScene().getWindow().getX() - getScene().getX() - getRadius(),
p.y - getScene().getWindow().getY() - getScene().getY() - getRadius()
);
setVisible(true);
logIt(e);
});
setOnDragDropped(e -> {
Dragboard db = e.getDragboard();
System.out.println("Dropped: " + db.getString() + " on " + name);
e.setDropCompleted(true);
e.consume();
logIt(e);
});
setOnDragOver(e -> {
if (e.getGestureSource() != this) {
e.acceptTransferModes(TransferMode.ANY);
logIt(e);
}
e.consume();
});
}
private void logIt(Event e) {
System.out.printf("%05d %s: %s\n", count++, name, e.getEventType().getName());
}
}
CircleDragApp.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.Random;
public class CircleDragApp extends Application {
private static final int W = 320;
private static final int H = 200;
private static final int R = 5;
private Random random = new Random(42);
public void start(Stage stage) throws Exception {
Pane pane = new Pane();
pane.setPrefSize(W, H);
for (int i = 0; i < 10; i++) {
CircleDrag circle = new CircleDrag(
random.nextInt(W - R) + R,
random.nextInt(H - R) + R,
i + ""
);
circle.setFill(Color.rgb(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
pane.getChildren().add(circle);
}
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Parting Thoughts
Lorand's solution which does not make use of the drag event handlers looks pretty good in comparison to what I have and may have a less quirks. Study both and choose the solution which appears best for your situation.
My general recommendation is that if you are going to be doing data transfer handling, then the drag and drop APIs might be a good approach. If you are not doing data transfer handling, then sticking with plain mouse events might be the best approach.
I am using JavaFX to build a GUI and I'm having problems on knowing the mouse location when resized. The idea is that if a mouse gets on the very edge of the GUI it changes to a double sided arrow indicating that you can now press the mouse and resize the window.
I need the location of the mouse pointer on this edge, but I don't know how to do that. I need to know in which direction the window is resized.
Updated Added new options and discussed pros and cons.
This is tricky. The issue is that the window keeps track of its top, left, width, and height. When it is resized from the right or bottom, things are easy enough: the width or height change. But when it is resized from the left, both x and width must change. These two changes do not happen atomically, as x and width are stored as two independent properties.
The first approach to this is to keep track of the mouse coordinates, and just see if it's in the left half or the right half. (Obviously you can do the same with the height.) This approach is independent of any implementation details, but the user can cause it to fail by being extremely careful with the mouse. If you move the mouse to the right edge of the window to the exact pixel of the window boundary, then resize, you can see incorrect output.
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
class MouseLocation {
double x,y ;
}
MouseLocation mouseLocation = new MouseLocation();
scene.setOnMouseMoved(event -> {
mouseLocation.x = event.getX();
mouseLocation.y = event.getY();
});
primaryStage.widthProperty().addListener((obs, oldWidth, newWidth) -> {
if (mouseLocation.x < primaryStage.getWidth() / 2) {
System.out.println("Resized from left");
} else {
System.out.println("Resized from right");
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The second approach is to keep track of the last known horizontal range of the window (minX and maxX), and update that range when the width changes. Then you can check to see whether the minX or maxX has changed. The problem with this approach is that it's dependent on undocumented implementation details. It appears (on my system, using the current version, etc) that when the window is resized from the left, x is changed first, then the width is changed. If that were to change in a subsequent release, the following would break:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
class MutableDouble {
double value ;
}
MutableDouble windowLeftEdge = new MutableDouble();
primaryStage.widthProperty().addListener((obs, oldWidth, newWidth) -> {
if (primaryStage.getX() == windowLeftEdge.value) {
System.out.println("Resized from right");
} else {
System.out.println("Resized from left");
}
windowLeftEdge.value = primaryStage.getX() ;
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The third approach (that I can think of) is to coalesce changes that happen quickly into a single change. This is a bit tricky to program correctly, so instead of doing it from scratch, I used the third party ReactFX framework which models "event streams" and has a built-in mechanism for combining events that happen in quick succession. This is probably the most robust of the three solutions presented here, but at the cost of either a degree of complexity, or the inclusion of an external framework.
import java.time.Duration;
import org.reactfx.Change;
import org.reactfx.EventStream;
import org.reactfx.EventStreams;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ReactFXVersion extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
ObservableValue<Bounds> windowBounds = Bindings.createObjectBinding(() ->
new BoundingBox(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight()),
primaryStage.xProperty(), primaryStage.yProperty(), primaryStage.widthProperty(), primaryStage.heightProperty());
EventStream<Change<Bounds>> bounds = EventStreams.changesOf(windowBounds)
.reduceSuccessions((previousChange, nextChange) ->
new Change<>(previousChange.getOldValue(), nextChange.getNewValue()),
Duration.ofMillis(10));
bounds.subscribe(boundsChange -> {
Bounds newBounds = boundsChange.getNewValue();
Bounds oldBounds = boundsChange.getOldValue();
if (newBounds.getWidth() != oldBounds.getWidth()) {
if (newBounds.getMinX() != oldBounds.getMinX()) {
System.out.println("Resized from left");
} else if (newBounds.getMaxX() != oldBounds.getMaxX()) {
System.out.println("Resized from right");
}
}
if (newBounds.getHeight() != oldBounds.getHeight()) {
if (newBounds.getMinY() != oldBounds.getMinY()) {
System.out.println("Resized from top");
} else if (newBounds.getMaxY() != oldBounds.getMaxY()) {
System.out.println("Resized from bottom");
}
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}