如何在JavaFX中将一个场景置于另一个场景之上

3
我正在编写一个小游戏。当在游戏中按下ESC键时,我想显示一个悬停在模糊的游戏菜单上方的暂停菜单。 我的做法是创建一个新场景,该场景包含一个StackPane覆盖了之前的根和暂停菜单根,然后我将之前根的不透明度设置为0.4。
然后,当点击暂停菜单中的恢复按钮时,我将不透明度改回1,并将之前的场景放回舞台,但此时该场景却被冻结了。有人知道原因吗?能帮助我实现这个吗?
这里是我创建新场景并将其放置在舞台上的部分代码:
        StackPane wrapper = new StackPane();
        previousScene = main.getPrimaryStage().getScene();
        previousScene.getRoot().setOpacity(.4);
        vBox.setId("pausedWrapper");
        wrapper.getChildren().add(previousScene.getRoot());
        wrapper.getChildren().add(vBox);
        scene = new Scene(wrapper, 1200, 700);
        return scene;

这里是我将其改回原来位置的部分:

        resumeGame.setOnAction(event -> {
            System.out.println("game resumed!");
            previousScene.getRoot().setOpacity(1);
            main.getPrimaryStage().setScene(previousScene);
        });

但是它不起作用,不透明度没有恢复正常,奇怪的是当我勾选声音框时,音乐会播放,但框没有被勾选,就像一切都在运行,但视图被冻结。

1个回答

10

一个节点不能同时成为两个不同场景图的一部分。您的代码中发生了这种情况,因为previousScene的根节点既是previousScene的一部分,又是您在第一个代码块中创建的新场景的一部分。最可能发生的情况是,在将其添加到第二个场景时,它从第一个场景中被移除(虽然很难从您发布的代码中判断出来)。

考虑改用Popup在现有窗口上方显示pauseMenu,或者只需使用带有无边框StageStyle的模态Stage,如下面的SSCCE示例:

import javafx.animation.Animation;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Modality;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

public class PauseExample extends Application {

    @Override
    public void start(Stage primaryStage) {

        Rectangle rect = new Rectangle(50, 50, 50, 50);
        rect.setFill(Color.CORAL);

        TranslateTransition animation = createAnimation(rect);

        Button pauseButton = new Button("Pause");

        Pane pane = new Pane(rect);
        pane.setMinSize(600, 150);

        BorderPane root = new BorderPane(pane, null, null, pauseButton, new Label("This is\nthe main\nscene"));

        pauseButton.setOnAction(e -> {
            animation.pause();
            root.setEffect(new GaussianBlur());

            VBox pauseRoot = new VBox(5);
            pauseRoot.getChildren().add(new Label("Paused"));
            pauseRoot.setStyle("-fx-background-color: rgba(255, 255, 255, 0.8);");
            pauseRoot.setAlignment(Pos.CENTER);
            pauseRoot.setPadding(new Insets(20));

            Button resume = new Button("Resume");
            pauseRoot.getChildren().add(resume);

            Stage popupStage = new Stage(StageStyle.TRANSPARENT);
            popupStage.initOwner(primaryStage);
            popupStage.initModality(Modality.APPLICATION_MODAL);
            popupStage.setScene(new Scene(pauseRoot, Color.TRANSPARENT));


            resume.setOnAction(event -> {
                root.setEffect(null);
                animation.play();
                popupStage.hide();
            });

            popupStage.show();
        });

        BorderPane.setAlignment(pauseButton, Pos.CENTER);
        BorderPane.setMargin(pauseButton, new Insets(5));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TranslateTransition createAnimation(Rectangle rect) {
        TranslateTransition animation = new TranslateTransition(Duration.seconds(1), rect);
        animation.setByX(400);
        animation.setCycleCount(Animation.INDEFINITE);
        animation.setAutoReverse(true);
        animation.play();
        return animation;
    }

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

哇,太棒了,谢谢 :) 但是对我没用,因为当游戏暂停时,“暂停游戏”按钮仍然有效并且可以被点击。 - yukashima huksay
在这种情况下,请使用模态窗口。请查看更新版本。 - James_D
哦!有没有办法消除游戏被点击时的噪音?另外,我不希望顶部的最小化、最大化和关闭按钮无效。(如果我有点技术上瘾,我很抱歉) - yukashima huksay
太好了!它完全按照我的要求运行,谢谢!哦,你的评论里有一些奇怪的拼写错误;)!非常感谢! - yukashima huksay
噪音来自您的操作系统,因此...您可以返回弹出窗口版本,并在显示弹出窗口时调用 primaryStage.getScene().getRoot().setDisable(true);,在隐藏它时调用 primaryStage.getScene().getRoot().setDisable(false);。尝试各种组合(并阅读文档):其中一个可能会给您所需的结果。 - James_D

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