如何拖动JavaFX的未装饰窗口(舞台)

21

我有一个没有装饰的窗户:

public static void initStartPage(final Stage primaryStage) {

        final Stage startPage = new Stage();
        startPage.initStyle(StageStyle.UNDECORATED);
        //startPage.initOwner(primaryStage);
        //startPage.toFront();
        Scene scene = new Scene(agentsPanel(), 900, 500);
        startPage.setScene(scene);
        startPage.show();

    }

我想知道如何制作一个可拖动的无装饰窗口?当用户用右键选择窗口并按住鼠标移动时,我想改变它的位置。

附言:我尝试了这个解决方案,但它没有起作用:

private static FlowPane flow;
    private static BorderPane bpi;

    public static void initStartPage(final Stage primaryStage) {

        final Stage startPage = new Stage();
        startPage.initStyle(StageStyle.UNDECORATED);
        startPage.initOwner(primaryStage);
        //startPage.toFront();
        Scene scene = new Scene(agentsPanel(primaryStage), 900, 500);
        startPage.setScene(scene);
        startPage.show();

    }

    private static double xOffset = 0;
    private static double yOffset = 0;

    public static BorderPane agentsPanel(final Stage primaryStage) {

        BorderPane bp = new BorderPane();
        bp.setPrefSize(900, 500);
        bp.setMaxSize(900, 500);

        HBox thb = new HBox(10); // Set spacing between each child into the HBox
        thb.setPadding(new Insets(15, 15, 15, 15));


        HBox bhb = new HBox(10); // Set spacing between each child into the HBox
        bhb.setPadding(new Insets(15, 15, 15, 15));

        bp.setTop(thb);
        bp.setBottom(bhb);
        bp.setCenter(navigationPanel());


        bp.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                xOffset = event.getSceneX();
                yOffset = event.getSceneY();
            }
        });
        bp.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                primaryStage.setX(event.getScreenX() - xOffset);
                primaryStage.setY(event.getScreenY() - yOffset);
            }
        });

        return bp;

    }

同样是在JavaFX 2中移动未装饰的舞台的副本。 - jewelsea
1
我更新了帖子。我测试了这段代码,但它不起作用。 - Peter Penzov
3个回答

41

只需将您的setOnMousePressed方法更改为以下内容:

bp.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                xOffset = primaryStage.getX() - event.getScreenX();
                yOffset = primaryStage.getY() - event.getScreenY();
            }
        });

并且将你的 setOnMouseDragged 设置为这样:

bp.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                primaryStage.setX(event.getScreenX() + xOffset);
                primaryStage.setY(event.getScreenY() + yOffset);
            }
        });

11

@Eeliya答案运行良好。但是,如果使用以下代码,则代码将更短,因为我们不需要声明变量。

每当触发setOnMouseDragged时,我们需要一遍又一遍地重新设置它,但我认为这并不会导致问题。

bp.setOnMousePressed(pressEvent -> {
    bp.setOnMouseDragged(dragEvent -> {
        primaryStage.setX(dragEvent.getScreenX() - pressEvent.getSceneX());
        primaryStage.setY(dragEvent.getScreenY() - pressEvent.getSceneY());
    });
});

希望这有所帮助。


工作得很好,看起来也很漂亮! - mXaln

0

你可以使用这个,它适用于舞台和警报(基本上是另一个舞台,但用于弹出消息)。该节点是该阶段的主节点。

//Make a Stage Draggable
public void DraggableStage(Node node, Stage stage, Alert alert ) {
    double[] xOffset = {0}, yOffset = {0};
    node.setOnMousePressed(event -> {
        if (stage != null && alert == null){
            xOffset[0] = stage.getX() - event.getScreenX();
            yOffset[0] = stage.getY() - event.getScreenY();
        } else if(stage == null && alert != null){
            xOffset[0] = alert.getX() - event.getScreenX();
            yOffset[0] = alert.getY() - event.getScreenY();
        }
    });

    node.setOnMouseDragged(event -> {
        if (stage != null && alert == null){
            stage.setX(event.getScreenX() + xOffset[0]);
            stage.setY(event.getScreenY() + yOffset[0]);
        } else if(stage == null && alert != null){
            alert.setX(event.getScreenX() + xOffset[0]);
            alert.setY(event.getScreenY() + yOffset[0]);
        }
    });
}

关于编程方面的内容:为了代码的卫生性,最好不要传递不必要的参数 - 而是为每个阶段/警报设置专用方法。 - kleopatra
为什么浪费时间并重复编码呢?这是个人选择的问题,如果你想的话可以使用分治法,但在这种情况下,我与内容以及我在过去几个小时中放置的所有其他内容都有关。 - Dan
请编辑它们以遵循命名约定..这样可以更轻松地阅读和理解。 - kleopatra
你正在将偏移量应用于主面板以拖动舞台(JavaFX中的窗口),因此......对我来说,命名约定还可以,但是开发人员可以根据自己的喜好进行命名。 - Dan
好的,实际上...不是这样的:规范存在是有原因的(使代码更易于一眼阅读和理解)。而且,在Java星球上,以大写字母开头的方法违反了惯例,总是如此——如果你还没有看到这一点,你可能需要阅读一下它们(请参见我的第一个评论)。 - kleopatra
接受批评是好的,但也需要知道如何批评。我使用了大驼峰命名法,所以我接受了批评,但请学会如何让意见成为代码逻辑的一部分,而不仅仅是一些技术细节,虽然这些细节是正确的,但意图是帮助社区的;追踪代码中的错误并测试它们,看看我是否错了 :) - Dan

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