【问题标题】:Why is Java not showing buttons on second scene为什么Java没有在第二个场景中显示按钮
【发布时间】:2019-04-27 18:32:44
【问题描述】:

我的程序中有三个场景。 当我启动它时,我看到了带有所有按钮的第一个场景。 然后,当我进入第二个场景时,我只看到标签,按钮没有出现。 在第三个场景中,一切正常,我看到了标签和按钮。

所以问题是,为什么我的按钮没有出现在我的第二个场景中?

我尝试切换按钮和场景的设置顺序,让场景2(音量)是第三个场景,第三个场景(分辨率)是第二个场景。 每次第二个场景都没有显示按钮。

package view.options;

import javafx.application.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Options extends Application {
    Scene optionsMenu, volumeMenu, resolutionMenu;

    // Create the labels
    Label optionslabel= new Label("This is the options scene");
    Label volumelabel= new Label("This is the volume scene");
    Label resolutionlabel= new Label("This is the resolution scene");
    Label labl_message = new Label("Volume settings");
    Label labl_generalvolume = new Label("General volume");
    Label labl_effectvolume = new Label("Effect volume");
    Label labl_musicvolume = new Label("Music volume");

    // Create the buttons
    Button optionsButton= new Button("Go to options");
    Button volumeButton= new Button("Go to volume settings");
    Button resolutionButton= new Button("Go to resolution settings");
    Button saveButton = new Button("save");
    Button exitButton = new Button("exit");

    // Create the sliders
    Slider slider_generalvolume;
    Slider slider_effectvolume;
    Slider slider_musicvolume;

    @Override
    public void start(Stage optionsStage) {
        // Setup the sliders
        slider_generalvolume = new Slider();
        slider_generalvolume.setMin(0);
        slider_generalvolume.setMax(100);
        slider_generalvolume.setValue(50);
        slider_generalvolume.setShowTickLabels(true);
        slider_generalvolume.setShowTickMarks(true);
        slider_generalvolume.setBlockIncrement(10);

        slider_effectvolume = new Slider();
        slider_effectvolume.setMin(0);
        slider_effectvolume.setMax(100);
        slider_effectvolume.setValue(50);
        slider_effectvolume.setShowTickLabels(true);
        slider_effectvolume.setShowTickMarks(true);
        slider_effectvolume.setBlockIncrement(10);

        slider_musicvolume = new Slider();
        slider_musicvolume.setMin(0);
        slider_musicvolume.setMax(100);
        slider_musicvolume.setValue(50);
        slider_musicvolume.setShowTickLabels(true);
        slider_musicvolume.setShowTickMarks(true);
        slider_musicvolume.setBlockIncrement(10);

        // Setup the main button
        optionsButton.setOnAction(e -> optionsStage.setScene(optionsMenu));
        volumeButton.setOnAction(e -> optionsStage.setScene(volumeMenu));
        resolutionButton.setOnAction(e -> optionsStage.setScene(resolutionMenu));
        exitButton.setOnAction(e -> Platform.exit());
        saveButton.setOnAction(e -> Platform.exit());

        // Setup the layout and add elements to it
        VBox optionsLayout = new VBox(20);
        optionsLayout.getChildren().addAll(optionslabel, volumeButton, resolutionButton, exitButton);
        optionsLayout.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-insets: 5;" +
                "-fx-border-radius: 5;" +
                "-fx-border-color: blue;");
        optionsMenu = new Scene(optionsLayout, 300, 250);

        VBox volumeLayout = new VBox(20);
        volumeLayout.getChildren().addAll(volumelabel, saveButton, optionsButton);
        volumeLayout.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-insets: 5;" +
                "-fx-border-radius: 5;" +
                "-fx-border-color: blue;");
        volumeMenu = new Scene(volumeLayout, 300, 250);

        VBox resolutionLayout = new VBox(20);
        resolutionLayout.getChildren().addAll(resolutionlabel, saveButton, optionsButton);
        resolutionLayout.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-insets: 5;" +
                "-fx-border-radius: 5;" +
                "-fx-border-color: blue;");
        resolutionMenu = new Scene(resolutionLayout, 300, 250);

        // Setup stage and start it
        optionsStage.setTitle("Options");
        optionsStage.setScene(optionsMenu);
        optionsStage.show();
    }

    public static void main(String[] args) {
        launch(args);
        System.out.println("exited successfully!");
    }
}

那么,该死的虫子在哪里? 我不明白。 是不是某种 Java 或 JavaFX 巫毒教你看不到第二个场景的按钮?

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    问题来自saveButtonoptionButton 来自layout.getChildren().addAll(..., saveButton, optionButton)。 Java FX 节点被限制为最多 1 个父节点和最多 1 个场景。尝试在多个地方使用它要么将其从旧父级中删除,要么导致异常。在您的情况下,旧的父级被删除并被新的父级替换。为了使问题可视化,您可以更改布局初始化的顺序,因此,您将看到卷布局将正常工作,但另一个则不行。

    因此,如果您为每个布局创建唯一的 saveButton 实例和 optionsButton,它将起作用。

    例子:

    Button saveButtonVolume = new Button("save");
    Button saveButtonResolution = new Button("save");
    
    // ...
    
    saveButtonVolume.setOnAction(e -> Platform.exit());
    saveButtonResolution.setOnAction(e -> Platform.exit());
    
    // ...
    
    resolutionLayout.getChildren().addAll(resolutionlabel, saveButtonResolution, optionsButtonResolution);
    volumeLayout.getChildren().addAll(volumelabel, saveButtonVolume, optionsButtonVolume);
    

    遗憾的是,我没有找到任何方法来复制或克隆 Java FX 节点,这可以简化问题(例如:saveButton.clone())。

    【讨论】:

    • 哦,伙计,我知道为什么我讨厌 Java xD 所以,saveButton 的唯一实例是 uefull(触发不同的保存例程)但我不知道我应该如何看待optionButton(因为它实际上是一个 back() 按钮)。
    • 我不知道,我也不这么认为。就个人而言,我会存储对先前场景 Scene lastScene; 的引用,然后在调用 optionsStage.setScene(...) 时使用该场景 :)
    • 是的,我觉得这很难看,但我没有看到任何其他解决方案。否则,您可以更改设计以将按钮放在 optionsMenu 布局上。
    • 嗯,我得看看我能做什么,谢谢你的帮助
    • 不客气!祝你好运! :)(如果它解决了您的问题,请确保接受我的回答):p
    【解决方案2】:

    所以,这是一个只有一个场景、舞台和布局的工作示例。 所有按钮都可以这样重复使用。这不是我通常喜欢的方式,但它可以工作并且使代码更短。

    package view.options;
    
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    public class Options extends Application {
        // Create the labels
        Label optionslabel= new Label("This is the options scene");
        Label volumelabel= new Label("This is the volume scene");
        Label resolutionlabel= new Label("This is the resolution scene");
        Label labl_message = new Label("Volume settings");
        Label labl_generalvolume = new Label("General volume");
        Label labl_effectvolume = new Label("Effect volume");
        Label labl_musicvolume = new Label("Music volume");
    
        // Create the buttons
        Button optionsButton= new Button("Go to options");
        Button volumeButton= new Button("Go to volume settings");
        Button resolutionButton= new Button("Go to resolution settings");
        Button saveButton = new Button("save");
        Button exitButton = new Button("exit");
    
        VBox theOneAndOnlyLayout = new VBox(20);    
        Scene theOneAndOnlyScene;
    
        @Override
        public void start(Stage theOneAndOnlyStage) {
            theOneAndOnlyLayout.setStyle("-fx-padding: 10;" +
                    "-fx-border-style: solid inside;" +
                    "-fx-border-width: 2;" +
                    "-fx-border-insets: 5;" +
                    "-fx-border-radius: 5;" +
                    "-fx-border-color: blue;");
    
            theOneAndOnlyScene = new Scene(theOneAndOnlyLayout, 300, 250);
    
            theOneAndOnlyLayout.getChildren().setAll(optionslabel, volumeButton, resolutionButton, exitButton);
    
            optionsButton.setOnAction(e -> {
                theOneAndOnlyStage.setTitle("Options");
                theOneAndOnlyLayout.getChildren().setAll(optionslabel, volumeButton, resolutionButton, exitButton);
            });
            volumeButton.setOnAction(e -> {
                theOneAndOnlyStage.setTitle("Volume");
                theOneAndOnlyLayout.getChildren().setAll(volumelabel, saveButton, optionsButton);
            });
            resolutionButton.setOnAction(e -> {
                theOneAndOnlyStage.setTitle("Resolution");
                theOneAndOnlyLayout.getChildren().setAll(resolutionlabel, saveButton, optionsButton);
            });
            exitButton.setOnAction(e -> Platform.exit());
            saveButton.setOnAction(e -> Platform.exit());
    
            // Setup stage and start it
            theOneAndOnlyStage.setTitle("Options");
            theOneAndOnlyStage.setScene(theOneAndOnlyScene);
            theOneAndOnlyStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
            System.out.println("exited successfully!");
        }
    }
    

    【讨论】:

    • 谢谢,这很好用。欣赏你的工作。你能告诉我你最喜欢的方法是什么吗?因为你写道,这不是你想要的。谢谢
    • 我担心这样的评论会变得太长。一般来说,如果没有某种应用程序框架,我不会启动任何真正的 JavaFX 项目,例如github.com/sialcasa/mvvmFX 。这将帮助您清晰地构建代码并在模型和 gui 之间保持清晰的分离。我也不会尝试重用单个控件,而是重用代码来按需创建视图,这些视图可以是更大视图的片段,也可以是完整的场景内容。
    • 非常感谢您的提示,我会试一试。祝你有美好的一天
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 2017-08-06
    相关资源
    最近更新 更多