trey5498
trey5498

Reputation: 35

JavaFX Window dragging snaps and is not smooth

I am working on an application that begins with an TRANSPARENT AnchorPane (no title bar and round corners). I want to be able to drag and move the window around. I have gotten it to work, but when I click it, the window snaps upwards to where you are dragging from the center instead of where you click.

CSS:

.root {
    -fx-background-radius: 20; 
    -fx-border-radius: 20;
    -fx-background-color: transparent;
}

Main.java:

public void start(Stage primaryStage) throws Exception {
    primaryStage.initStyle(StageStyle.TRANSPARENT);
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(Main.class.getResource("../Scenes/Login.fxml"));

    //Creates the layout for the new scene
    AnchorPane layout = (AnchorPane) loader.load();             
    Scene scene = new Scene(layout);
    scene.setFill(Color.TRANSPARENT);
    scene.getStylesheets().add(getClass().getResource("../StyleSheets/application.css").toExternalForm());
    LoginController.allowDrag(layout, primaryStage);

    primaryStage.setScene(scene);   
    primaryStage.setResizable(false);
    primaryStage.show();
}

Controller:

private static final Rectangle2D SCREEN_BOUNDS = Screen.getPrimary().getVisualBounds();

public static void allowDrag(AnchorPane root, Stage primaryStage) {
    root.setOnMousePressed((MouseEvent mouseEvent1) -> {
            xOffset = mouseEvent1.getSceneX();
            yOffset = mouseEvent1.getScreenY();
    });

    root.setOnMouseDragged((MouseEvent mouseEvent2)-> {
            if (!mouseEvent2.isPrimaryButtonDown()) return;

            //Ensures the stage is not dragged past the taskbar
            if (mouseEvent2.getScreenY()<(SCREEN_BOUNDS.getMaxY()-20))
                primaryStage.setY(mouseEvent2.getScreenY() - yOffset);

            primaryStage.setX(mouseEvent2.getScreenX() - xOffset);
            primaryStage.setY(mouseEvent2.getScreenY() - yOffset);
    });

    root.setOnMouseReleased((MouseEvent mouseEvent3)-> {
        //Ensures the stage is not dragged past top of screen
        if (primaryStage.getY()<0.0) primaryStage.setY(0.0);
    });
}

I have a feeling that I need to account for where the cursor is, but I am not sure how to. Am I correct or is there something easier I am missing?

Upvotes: 2

Views: 747

Answers (2)

NAVEED SHAHZAD
NAVEED SHAHZAD

Reputation: 17

Well done that is complete solution of this problem. if you want to drag window of javafx login then you can use this.

package com.systems.auth;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import javafx.scene.input.MouseEvent;
import javafx.stage.StageStyle;
/**
 * JavaFX App
 */
public class App extends Application {

    private static Scene scene;
    private double gapX = 0, gapY = 0;

    @Override
    public void start(Stage stage) throws IOException {
        Parent root = loadFXML("login");
        scene = new Scene(root, 700, 500);
        stage.setResizable(false);
        stage.initStyle(StageStyle.DECORATED.UNDECORATED);
        root.setOnMouseDragged(e -> this.dragStage(e, stage));
        root.setOnMouseMoved(e -> this.calculateGap(e, stage));
        stage.setScene(scene);
        stage.show();
    }
    
  

    private void calculateGap(MouseEvent event, Stage stage) {
        gapX = event.getScreenX() - stage.getX();
        gapY = event.getScreenY() - stage.getY();
    }

    private void dragStage(MouseEvent event, Stage stage) {
        stage.setX(event.getScreenX() - gapX);
        stage.setY(event.getScreenY() - gapY);
    }

    static void setRoot(String fxml) throws IOException {
        scene.setRoot(loadFXML(fxml));
    }

    private static Parent loadFXML(String fxml) throws IOException {
        System.out.print(App.class.getResource(fxml + ".fxml"));
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

    public static void main(String[] args) {
        launch();
    }

}

Upvotes: 0

Shekhar Rai
Shekhar Rai

Reputation: 2058

Yes! you're right! And I have a simpler workaround for you to do so :)

Add the following code in your Main.java class,

private double gapX = 0, gapY = 0;

private void calculateGap(MouseEvent event, Stage stage) {
    gapX = event.getScreenX() - stage.getX();
    gapY = event.getScreenY() - stage.getY();
}

private void dragStage(MouseEvent event, Stage stage) {
    stage.setX(event.getScreenX() - gapX);
    stage.setY(event.getScreenY() - gapY);
}
  • calculateGap(MouseEvent event, Stage stage) as method-name says, it calculates the gap between MouseEvent and Stage coordinates.
  • dragStage(MouseEvent event, Stage stage) It lets you drag your stage based on the MouseEvent and the calculated-gap.

Set these EventHandlers on your parent root layout in start() method,

layout.setOnMouseDragged(e -> this.dragStage(e, primaryStage));
layout.setOnMouseMoved(e -> this.calculateGap(e, primaryStage));

Now you can drag your window smoothly :)

Upvotes: 5

Related Questions