在JavaFX 2中移动未装饰的舞台

26

我一直在尝试移动一个未装饰的窗口,使用以下鼠标事件监听器:

  • onPressed (按下)
  • onReleased (释放)
  • onDragged(拖动)

这些事件是针对一个矩形的。我的想法是通过点击矩形并拖动整个窗口来移动未装饰的窗口。

@FXML
protected void onRectanglePressed(MouseEvent event) {
    X = primaryStage.getX() - event.getScreenX();
    Y = primaryStage.getY() - event.getScreenY();
}
@FXML protected void onRectangleReleased(MouseEvent event) { primaryStage.setX(event.getScreenX()); primaryStage.setY(event.getScreenY()); }
@FXML protected void onRectangleDragged(MouseEvent event) { primaryStage.setX(event.getScreenX() + X); primaryStage.setY(event.getScreenY() + Y); }

使用这些事件,我只能够在按下矩形并开始拖动窗口时稍微移动窗口。但是,在我释放按钮时,窗口会移动到矩形所在的位置。

提前感谢。


不需要处理 onRectangleReleased 事件。 - Uluk Biy
5个回答

32

我创建了一个无装饰窗口中的动画时钟样例,你可以拖动它,这里是示例

示例中的相关代码如下:

// allow the clock background to be used to drag the clock around.
final Delta dragDelta = new Delta();
layout.setOnMousePressed(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    // record a delta distance for the drag and drop operation.
    dragDelta.x = stage.getX() - mouseEvent.getScreenX();
    dragDelta.y = stage.getY() - mouseEvent.getScreenY();
  }
});
layout.setOnMouseDragged(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    stage.setX(mouseEvent.getScreenX() + dragDelta.x);
    stage.setY(mouseEvent.getScreenY() + dragDelta.y);
  }
});

...

// records relative x and y co-ordinates.
class Delta { double x, y; } 

代码看起来与你的相似,所以我不太确定为什么你的代码对你不起作用。


是的,差不多就是这样。终于找到了解决方案,我的错误在于使用了错误的事件。我一直在使用场景构建器。但是实现了setOnMouseDragged之后,一切都变得完美了。谢谢! - Antonio J.
我注意到这种方法的刷新率比系统窗口拖动要低。但愿我知道如何使用系统窗口位置重定位器。 - PathToLife
1
设置舞台为无装饰模式会移除窗口10对快速边缘调整的支持。 - PathToLife
1
@PathToLife https://dev59.com/_WIk5IYBdhLWcg3wPb-B - SedJ601

14

我正在使用这个解决方案,通过拖动任何包含的节点来拖动未装饰的舞台。

private void addDraggableNode(final Node node) {

    node.setOnMousePressed(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent me) {
            if (me.getButton() != MouseButton.MIDDLE) {
                initialX = me.getSceneX();
                initialY = me.getSceneY();
            }
        }
    });

    node.setOnMouseDragged(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent me) {
            if (me.getButton() != MouseButton.MIDDLE) {
                node.getScene().getWindow().setX(me.getScreenX() - initialX);
                node.getScene().getWindow().setY(me.getScreenY() - initialY);
            }
        }
    });
}

4

根据jewelsea的回复,我在我的start()方法中创建了两个lambda表达式,直接在场景上设置MouseListeners。运行良好 :)

private double xOffset;
private double yOffset;
         /*
        The two following lambda expressions makes it possible to move the application without the standard StageStyle
         */
        //Lambda mouse event handler
        scene.setOnMousePressed(event -> {
            xOffset = primaryStage.getX() - event.getScreenX();
            yOffset = primaryStage.getY() - event.getScreenY();
        });
        //Lambda mouse event handler
        scene.setOnMouseDragged(event -> {
            primaryStage.setX(event.getScreenX() + xOffset);
            primaryStage.setY(event.getScreenY() + yOffset);
        });enter code here

3

我猜测您的问题可能是:

onRectangleReleased()

将完全相同的坐标从您的位置传递

onRectanglePressed()

这是因为如文档所述,MouseEvent类的getX()方法返回:

相对于 MouseEvent 源的原点的事件水平位置。

因此,当你释放鼠标时,实际上会将矩形放置在你第一次按下鼠标时的位置。

顺便说一句,我使用一个包含矩形的 StackPane,然后应用以下代码:

private void addDragListeners(final Node n){
       n.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent me) {
                if(me.getButton()!=MouseButton.MIDDLE)
                {
                    initialX = me.getSceneX();
                    initialY = me.getSceneY();
                }
                else
                {
                    n.getScene().getWindow().centerOnScreen();
                    initialX = n.getScene().getWindow().getX();
                    initialY = n.getScene().getWindow().getY();
                }

            }
       });

       n.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent me) {
                if(me.getButton()!=MouseButton.MIDDLE)
                {
                    n.getScene().getWindow().setX( me.getScreenX() - initialX );
                    n.getScene().getWindow().setY( me.getScreenY() - initialY);
                }
            }
        });
}

addDragListeners(mainStackPane);

此外,我使用中键将我的窗口居中显示在屏幕上。希望这能有所帮助。干杯!


谢谢。我正在使用场景构建器创建GUI,但是我使用了错误的拖动事件。我实现了onMouseDragged并且一切正常。谢谢! - Antonio J.

1
double x, y;

private void addDragListeners(final Node n, Stage primaryStage){

    n.setOnMousePressed((MouseEvent mouseEvent) -> {
        this.x = n.getScene().getWindow().getX() - mouseEvent.getScreenX();
        this.y = n.getScene().getWindow().getY() - mouseEvent.getScreenY();
    });

    n.setOnMouseDragged((MouseEvent mouseEvent) -> {
        primaryStage.setX(mouseEvent.getScreenX() + this.x);
        primaryStage.setY(mouseEvent.getScreenY() + this.y);
    });
}

public void start(Stage primaryStage) {

    try {

        ...

        addDragListeners(mainPane, primaryStage);

    } catch (Exception e) {
        e.printStackTrace(System.out);
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接