如何在JavaFX中切换场景

如何在JavaFX中切换场景,java,javafx,fxml,scenebuilder,scene,Java,Javafx,Fxml,Scenebuilder,Scene,我在很多页面上都看过,试图找出如何切换场景,但都没有成功 我有一个计算器,我的目标是选择一个菜单选项来更改计算器(即:基本和科学)。现在我只是在测试,所以这里是我到目前为止与这个问题相关的代码(我使用的是场景生成器): 编辑 我已经试过很多东西了。不管怎样,我总是得到这个NullPointerException。我有一种感觉,这可能与在场景生成器中设置某些内容有关,但我一直无法找到答案 Exception in thread "JavaFX Application Thread" java.la

我在很多页面上都看过,试图找出如何切换场景,但都没有成功

我有一个计算器,我的目标是选择一个菜单选项来更改计算器(即:基本和科学)。现在我只是在测试,所以这里是我到目前为止与这个问题相关的代码(我使用的是场景生成器):

编辑 我已经试过很多东西了。不管怎样,我总是得到这个NullPointerException。我有一种感觉,这可能与在场景生成器中设置某些内容有关,但我一直无法找到答案

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.control.MenuItem.fire(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at    com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
... 44 more
Caused by: java.lang.NullPointerException
at CalculatorMain.changeScene(CalculatorMain.java:75)
at CalculatorMain.handleMenuOption(CalculatorMain.java:64)
... 53 more




at CalculatorMain.changeScene(CalculatorMain.java:75)
This is at:stage . getScene() . setRoot(pane);


at CalculatorMain.handleMenuOption(CalculatorMain.java:64)
This is at:changeScene ("TestSwitch.fxml");
工作代码:

我使用下面的建议,并使用此代码使其工作:

private Stage stage;

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

@Override
public void start(Stage primaryStage) throws Exception
{
    this.stage = primaryStage;
    FXMLLoader loader = new FXMLLoader(getClass()
            .getResource("calculator.fxml"));
    Parent root = (Parent)loader.load();
    BasicCalculatorView controller = (BasicCalculatorView)loader.getController();
    controller.setModel(new BasicCalculatorModelTest(controller));
    controller.setLogic(this);
    primaryStage.setTitle("Calculator");
    primaryStage.setScene(new Scene(root));
    primaryStage.show();
}

public void switchScene(String fxmlFile)
{

    FXMLLoader loader = new FXMLLoader(getClass()
            .getResource(fxmlFile));
    Parent root;
    try 
    {
        root = (Parent)loader.load();
        if(fxmlFile.equals("calculator.fxml"))
        {
            BasicCalculatorView controller = (BasicCalculatorView)loader.getController();
            controller.setModel(new BasicCalculatorModelTest(controller));
            controller.setLogic(this);
        }
        else if(fxmlFile.equals("TestSwitch.fxml"))
        {
            TestSwitch controller = (TestSwitch)loader.getController();
            controller.setLogic(this);
        }
        this.stage.setScene(new Scene(root));
    } 
    catch (IOException e)
    {
        e.printStackTrace();
    }

}

不要切换
场景
,而是在现有的
场景

上切换根节点。如果要继续更改场景,可以这样做(请注意,该阶段是应用程序的一个成员):

然而,正如@Eugene_Ryzhikov所指出的,改变现有场景的根内容是更好的解决方案:

public void changeScene(String fxml){
    Parent pane = FXMLLoader.load(
           getClass().getResource(fxml));

   primaryStage.getScene().setRoot(pane);
}

我写这个控制器是为了跟踪不同的场景

public class ScreenController {
    private HashMap<String, Pane> screenMap = new HashMap<>();
    private Scene main;

    public ScreenController(Scene main) {
        this.main = main;
    }

    protected void addScreen(String name, Pane pane){
         screenMap.put(name, pane);
    }

    protected void removeScreen(String name){
        screenMap.remove(name);
    }

    protected void activate(String name){
        main.setRoot( screenMap.get(name) );
    }
}

这是一个全屏应用程序的变通方法,每次舞台切换场景时都会显示MacOS全屏过渡。

我只是跑向同一个问题,完美地解决了我的问题,同时又简洁明了

@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!

Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));

}


我编写了一个库,使切换场景变得非常简单。您只需为Integer类型的每个场景选择一个唯一的ID,然后添加带有一行代码的场景。当需要显示场景时,可以从项目中的任何类通过调用该方法并将场景ID传递给它来实现


与Maven import xml一起使用。

我已经尝试过了,但一直出现空指针异常。在收到关于同一件事的两条评论后,我决定发布我的异常消息,请参见上文。在您的代码中,您混合了
应用程序
和FXML控制器的概念。每个都有不同的初始化生命周期。FXML控制器基于依赖项注入原理,应该在
init
方法中进行初始化。请阅读FXML控制器。您还可以看到以下内容,因此如何切换场景。我尝试使用init方法并设置一个字符串参数。如果我传入一个字符串,如“test”,并使用syso打印结果,它将打印test。但是,如果我用FXML文件传入一个字符串并尝试设置场景,它会给我一个空指针异常。我尝试过这个,但我一直得到一个空指针异常。在收到关于同一事物的两条评论后,我决定发布我的异常消息,请参见上文。获取
NullPointerException
的行中的代码是什么?在上文中,我添加了我得到的异常,底部有注释。但是我厌倦了几个类似的例子,没有使用场景生成器,它工作得非常好,因此可以肯定的是,场景生成器中的某些东西有可能在
start
方法中作为参数传递的stage没有分配给成员
primaryStage
?这将导致第
primaryStage.getScene().setRoot(窗格)
行出现
NullPointerException
。我更新了代码示例以包含
start
方法的片段。对不起,我知道这是一篇旧文章。你为什么这样做呢?primaryStage=primaryStage?为什么不忽略
start()
method参数并使用
this.primaryStage
?请编辑您的第一个答案并添加来自其他答案的片段(并解释它们如何/为什么按照注释中的建议解决问题),这样您就知道我在2年前发布了这篇文章。我想我所做的只是从答案中得到建议,在谷歌上做了更多的搜索,然后找到了答案。我对编程还是很陌生,不知道自己在做什么。有这么长的代码示例,一些解释会很酷。@ChristianM我喜欢你对这个答案给出反馈的方式…-)
public class ScreenController {
    private HashMap<String, Pane> screenMap = new HashMap<>();
    private Scene main;

    public ScreenController(Scene main) {
        this.main = main;
    }

    protected void addScreen(String name, Pane pane){
         screenMap.put(name, pane);
    }

    protected void removeScreen(String name){
        screenMap.remove(name);
    }

    protected void activate(String name){
        main.setRoot( screenMap.get(name) );
    }
}
ScreenController screenController = new ScreenController(scene);
screenController.add("calculator", FXMLLoader.load(getClass().getResource( "calculator.fxml" )));
screenController.add("testSwitch", FXMLLoader.load(getClass().getResource( "TestSwitch.fxml" )));
screenController.activate("calculator");
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!

Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));

}
TypesController.java
package todoapp;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.stage.Stage;

public class TypesController implements Initializable {
@FXML
private CheckBox c1;
@FXML
private CheckBox c2;
public void clicked(ActionEvent e) throws IOException {
Parent home_page_parent =FXMLLoader.load(getClass().getResource("AddDcuFXML.fxml"));
Scene home_page_scene = new Scene(home_page_parent);
Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
app_stage.hide(); //optional
app_stage.setScene(home_page_scene);
app_stage.show();
}
public void clicked1(ActionEvent e) throws IOException {
Parent home_page_parent =   FXMLLoader.load(getClass().getResource("AddDcuFXML.fxml"));
    Scene home_page_scene = new Scene(home_page_parent);
    Stage app_stage = (Stage) ((Node)e.getSource()).getScene().getWindow();
   app_stage.hide(); //optional
   app_stage.setScene(home_page_scene);
   app_stage.show();
   }
  @Override
  public void initialize(URL arg0, ResourceBundle arg1) {
 // TODO Auto-generated method stub
  } }
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
 <?import javafx.scene.text.*?>
 <?import java.lang.*?>
 <?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="491.0" prefWidth="386.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="todoapp.TypesController">
<children>
  <CheckBox fx:id="c1" layoutX="55.0" layoutY="125.0" mnemonicParsing="false" onAction="#clicked" text="ADD dcu" />
  <CheckBox fx:id="c2" layoutX="55.0" layoutY="177.0" mnemonicParsing="false" onAction="#clicked1" text="Display dcu" />
  <Label layoutX="31.0" layoutY="58.0" prefHeight="37.0" prefWidth="276.0" text="Choose any one of the options" textFill="#1b29cd">
     <font>
        <Font name="Arial Bold" size="18.0" />
     </font>
  </Label>
</children>