Lukas Hieronimus Adler
Lukas Hieronimus Adler

Reputation: 1094

JavaFX Container Draggable

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.

Upvotes: 0

Views: 1628

Answers (1)

James_D
James_D

Reputation: 209225

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);
    }
}

Upvotes: 1

Related Questions