Search code examples
javafxdraggablestage

JavaFX: Loosing undecorated window while dragging it


I have an undecorated stage where I 've added an AnchorPane which contains two AnchorPains (a titlebar and a mainContent). To use this window like a normal window I implemented p.e. functions for resizing it on the sides and dragging it on the titlebar. To drag the window I analyze the MouseEvents onMouseDragged and onMousePressed (see source code below). The source code is working basically. But I have the problem that the window will not be moved if I move the mouse too fast. At the beginning the mouse is on the titlebar. After this I'm moving the mouse too fast to one side, so that it is outside of the window and it will be not dragged anymore. As soon as I go back to the titlebar I can move it again. Does anybody has a suggestion how this problem can be solved? Is it possible to bind the window to the mouse Cursor?

Here is my source code:

    titleContent.setOnMousePressed(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent mouseEvent) {
                Stage stage = (Stage) titleContent.getScene().getWindow();
                Screen screen = Screen.getPrimary();
                Rectangle2D bounds = screen.getVisualBounds();

                if (mouseEvent.getClickCount()==1){
                // record a delta distance for the drag and drop operation.
                    if (stage.getWidth()==bounds.getMaxX() && stage.getHeight()==bounds.getMaxY()){
                        wasMaximized =true;
                    }

                    if(!wasMaximized){
                        dragDelta.x = stage.getX() - mouseEvent.getScreenX();
                        dragDelta.y = stage.getY() - mouseEvent.getScreenY();
                    }
                    else{
                        dragDelta.x=-1*minWidth/2;
                        dragDelta.y=0;
                        wasMaximized=false;
                    }
                }
        }
    });

    titleContent.setOnMouseDragged(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent mouseEvent) {
                Scene scene = (Scene) titleContent.getScene();
                if (!(mouseEvent.getX() < border || mouseEvent.getX() > scene.getWidth() -border) && !(mouseEvent.getX() < border && mouseEvent.getY() > scene.getHeight() -border)){
                    Stage stage = (Stage) titleContent.getScene().getWindow();
                    Screen screen = Screen.getPrimary();
                    Rectangle2D bounds = screen.getVisualBounds();


                    if (stage.getWidth()==bounds.getMaxX() && stage.getHeight()==bounds.getMaxY()){
                        stage.setWidth(minWidth);
                        stage.setHeight(minHeight);
                    }

                    stage.setX(mouseEvent.getScreenX() + dragDelta.x);
                    stage.setY(mouseEvent.getScreenY() + dragDelta.y);
                }

    }
  });

Solution

  • I've found the solution. For everyone how is interested in it: The problem is the if-statement in the titlecontent.setOnMouseDragged Function. The function is just called if the mouse is tragged on the given element. That's why it is not necessary to use an if-statement there. The correct functions looks like:

    titleContent.setOnMouseDragged(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent mouseEvent) {
                Scene scene = (Scene) titleContent.getScene();
                if (!(mouseEvent.getX() < border || mouseEvent.getX() > scene.getWidth() -border) && !(mouseEvent.getX() < border && mouseEvent.getY() > scene.getHeight() -border)){
                    Stage stage = (Stage) titleContent.getScene().getWindow();
                    Screen screen = Screen.getPrimary();
                    Rectangle2D bounds = screen.getVisualBounds();
    
    
                    if (stage.getWidth()==bounds.getMaxX() && stage.getHeight()==bounds.getMaxY()){
                        stage.setWidth(minWidth);
                        stage.setHeight(minHeight);
                    }
    
                    stage.setX(mouseEvent.getScreenX() + dragDelta.x);
                    stage.setY(mouseEvent.getScreenY() + dragDelta.y);
                }
    
    }
    

    Consequently, here is a complete solution for dragging and resizing an undecorated stage. Hopefully it helps.