Jaman
Jaman

Reputation: 125

Stop dragging Node out of a Pane

I have a StackPane which I can drag around a Pane (the pane is the parent layout of the stack pane) but at the moment I can drag this out of the Pane. Currently, I cannot find a way to stop the StackPane moving out the Pane when it is dragged out of the Pane.

My event handler when you press the StackPane:

EventHandler<MouseEvent> circleOnMousePressedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {

                currentStackPane  = ((StackPane)(t.getSource()));
                orgSceneX = t.getSceneX();
                orgSceneY = t.getSceneY();
                layoutX =  currentStackPane.getLayoutX();
                layoutY =  currentStackPane.getLayoutY();

            }
        };

My event handler when i drag the StackPane:

EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {


                double offsetX = t.getSceneX() - orgSceneX;
                double offsetY = t.getSceneY() - orgSceneY;
                currentStackPane.setTranslateX(offsetX);
                currentStackPane.setTranslateY(offsetY);
             }
        };

My event handler when I let go of the mouse:

            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {

                currentStackPane.setLayoutX(layoutX + ((StackPane)(t.getSource())).getTranslateX());
                currentStackPane.setLayoutY(layoutY + ((StackPane)(t.getSource())).getTranslateY());
                currentStackPane.setTranslateX(0);
                currentStackPane.setTranslateY(0);
            }
        };
        return circleOnMouseReleaseEventHandler;

}

Is there a way I can keep the stack pane only draggable within the pane.

Thank you.

EDIT:

What I have tried:

I created this method:

private boolean outSideParentBounds( Bounds childBounds, double newX, double newY) {

    Bounds parentBounds = centerPane.getLayoutBounds();

    //check if too left
    if( parentBounds.getMaxX() <= (newX + childBounds.getMaxX()) ) {
        return true ;
    }

    //check if too right
    if( parentBounds.getMinX() >= (newX + childBounds.getMinX()) ) {
        return true ;
    }

    //check if too down
    if( parentBounds.getMaxY() <= (newY + childBounds.getMaxY()) ) {
        return true ;
    }

    //check if too up
    if( parentBounds.getMinY() >= (newY + childBounds.getMinY()) ) {
        return true ;
    }

    return false;
}

And my dragging event handler now looks like this:

EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {


                double offsetX = t.getSceneX() - orgSceneX;
                double offsetY = t.getSceneY() - orgSceneY;

                if( outSideParentBounds(currentStackPane.getLayoutBounds(), layoutX + ((StackPane)(t.getSource())).getTranslateX(), 
                        layoutY + ((StackPane)(t.getSource())).getTranslateY()) ) {  

                    return; 
                }

                currentStackPane.setTranslateX(offsetX);
                currentStackPane.setTranslateY(offsetY);

            }
        };

But this doesn't seem to work once I drag it out of the pane it just gets stuck on the edge of pane and you cannot drag it around anymore.

Upvotes: 0

Views: 788

Answers (1)

Sai Dandem
Sai Dandem

Reputation: 9869

One issue I can notice is you are not considering the offSet values in computing outSideParentBounds. And also you cannot update translate values ONLY when condition is satisfied. Instead, you have to ALWAYS update the translate values to required values in the drag handler.

Your drag handler should be changed as below::

EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = e -> {
            // Offset of drag
            double offsetX = e.getSceneX() - sceneX;
            double offsetY = e.getSceneY() - sceneY;

            // Taking parent bounds
            Bounds parentBounds = currentStackPane.getParent().getLayoutBounds();

            // Drag node bounds
            double currPaneLayoutX = currentStackPane.getLayoutX();
            double currPaneWidth = currentStackPane.getWidth();
            double currPaneLayoutY = currentStackPane.getLayoutY();
            double currPaneHeight = currentStackPane.getHeight();

            if ((currPaneLayoutX + offsetX > -1) && (currPaneLayoutX + offsetX < parentBounds.getWidth() - currPaneWidth)) {
                // If the dragNode bounds is within the parent bounds, then you can set the offset value.
                currentStackPane.setTranslateX(offsetX);
            } else if (currPaneLayoutX + offsetX < 0) {
                // If the sum of your offset and current layout position is negative, then you ALWAYS update your translate value to negative layout value
                // which makes the final layout position to 0 in mouse released event.
                currentStackPane.setTranslateX(-currPaneLayoutX);
            } else {
                // If your dragNode bounds are outside parent bounds,ALWAYS setting the translate value that fits your node at end.
                currentStackPane.setTranslateX(parentBounds.getWidth() - currPaneLayoutX - currPaneWidth);
            }

            if ((currPaneLayoutY + offsetY < parentBounds.getHeight() - currPaneHeight) && (currPaneLayoutY + offsetY > -1)) {
                currentStackPane.setTranslateY(offsetY);
            } else if (currPaneLayoutY + offsetY < 0) {
                currentStackPane.setTranslateY(-currPaneLayoutY);
            } else {
                currentStackPane.setTranslateY(parentBounds.getHeight() - currPaneLayoutY - currPaneHeight);
            }
        };

The reason to ALWAYS update is :: the drag event handler will not be called for every pixel you drag. Say suppose you want to drag a node by 500px. If you print the offsetX/Y values, you will notice that the offsetX/Y values are NOT ALWAYS sequential or will not print for each and every pixel. It may jump some values. They may vary based on the speed of your drag. For that reason you may get jumped over your desired end point.

To verify this, once you are familiar with the above code, try commenting the "else" parts of the code and keep only the first if condition. Try dragging the node speedly, you will notice that your node will end randomly far ahead/behind the desired end point.

Upvotes: 1

Related Questions