在JavaFXActionEvent中调用方法

在JavaFXActionEvent中调用方法,java,javafx,actionevent,Java,Javafx,Actionevent,我是JavaFX新手,我想创建一个视图类,当按下按钮触发事件时,该类将调用控制器中的方法。我的代码如下: package spacetrader.menu; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import javafx.event.Act

我是JavaFX新手,我想创建一个视图类,当按下按钮触发事件时,该类将调用控制器中的方法。我的代码如下:

package spacetrader.menu;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import spacetrader.Window;

public class MenuView implements Initializable {
    public Window window;
    public MenuCtrl menuCtrl;

    @FXML
    Button start;
    @FXML
    Pane background;
    @FXML
    Button exit;

    public MenuView() {};

    public MenuView(Window aWindow, MenuCtrl aMenuCtrl) {
        window = aWindow;
        menuCtrl = aMenuCtrl;
    }

    void renderMainMenu() {
        try {
            window.loadFXML(new FXMLLoader((getClass().getResource("MainMenu.fxml"))));
        } catch (IOException ex) {
            Logger.getLogger(MenuView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        start.setOnAction((ActionEvent event) -> menuCtrl.newGame());
        exit.setOnAction((ActionEvent event) -> menuCtrl.closeApplication());
    }
}
这可以编译,但当我运行它并按下按钮时,lambda表达式上会出现空指针异常。异常是指“menuCtrl”。我应该如何设置程序以进行按钮调用menuCtrl.newGame()

以下是我已经尝试过的:

  • 我已经将setOnAction命令移动到不同方法之间
  • 用System.out.prinln语句替换对menuCtrl方法的调用,以确认此操作是否有效。是的
  • 我用System.out.println(this)替换了menuCtrl方法,以确保没有范围问题。它打印“spacetrader.menu”。MenuView@74f51979“果然如此
  • 将Lambda表达式转换为匿名内部类
  • 用一块木头做lambda的尸体

您可以尝试使用
场景生成器
,其中提供了拖放功能,您可以在几秒钟内设计屏幕。在代码部分中,您只需声明方法名称并在代码处理程序类中实现该方法


您可以从

获得它,因为您有两个构造函数。我猜您正在某处加载一个FXML,它将使用no-args构造函数实例化您的控制器。在这种情况下,menuCtrl未初始化


如果要在FXML中实例化menuCtrl,请在字段中添加@FXML注释。

您的设置是不寻常的,因为您的控制器类(称为
MenuView
)是调用(通过
窗口
类间接调用)FXMLLoader加载方法的类。
fxmloader
解析FXML,查看
fx:controller
属性,然后使用默认(无参数)构造函数实例化它。(我在此假设您没有在
窗口中的
fxmloader
上调用
setController
setControllerFactory
),因此您有两个控制器实例:一个是创建加载程序的实例(initialize()方法不会被调用,
@FXML
-注释字段也不会被注入),并且由
fxmloader
创建的字段(它调用了无参数构造函数,因此该实例的
窗口和
menuCtrl
字段不会被初始化)

您应该重构它,以便创建FXMLLoader并将其传递给窗口类以便在其他地方加载(即,不实例化控制器),或者应该在FXMLLoader上显式设置控制器。您可以通过两个步骤实现后者:

  • 从main menu.fxml中删除
    fx:controller
    属性
  • 将控制器显式设置为已在
    renderMainMenu
    方法中创建的实例:
  • --


    这个类是它加载的同一个FXML的控制器类吗?(即main menu.fxml是否在根元素中有
    fx:controller=“MenuView”
    )这将是一个不寻常的设置,至少在这里是这样。是的,main menu.fxml中的fx:controller是MenuView。为什么这么奇怪?因为您必须创建控制器的一个实例才能加载FXML,然后FXML将创建控制器的另一个实例。通常,您会从不同的类加载FXML(例外可能是如果您使用的是(看起来非常不同)。啊,这是有道理的。我稍后会尝试。先生,您真是太棒了。我对FX的体系结构是如何工作的有一个完全错误的想法,这就彻底解决了问题。
    FXMLLoader loader = new FXMLLoader((getClass().getResource("MainMenu.fxml"))) ;
    loader.setController(this);
    window.loadFXML(loader);