2014-10-03 69 views
0

我是JavaFX的新手,我想创建一个视图类,当通过按钮触发事件时,该类将调用Controller中的方法。我的代码如下:在Java Fx ActionEvent中调用方法

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方法,以确保没有范围问题。按预期打印“[email protected]”。
  • 转换的Lambda表达式来使用的块作为拉姆达的身体匿名内部类
+0

这是类加载相同FXML控制器类? (即MainMenu.fxml是否具有'fx:controller =“MenuView”'作为根元素中的一个属性?)这将是一个不寻常的设置,至少在这里是这样。 – 2014-10-03 12:10:40

+0

是的MainMenu.fxml中的fx:控制器是MenuView。为什么这很奇怪? – jaxoncreed 2014-10-03 16:40:42

+0

因为您必须创建控制器的一个实例才能加载FXML,然后创建另一个控制器实例。通常情况下,您可以从不同的类加载FXML(如果您使用的是[动态根目录],则可能是异常(http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files /introduction_to_fxml.html#custom_components)(看起来很不一样) – 2014-10-03 17:47:46

回答

1

由于您的控制器类(您称为MenuView)是您调用(通过您的Window类间接)FXMLLoader的加载方法的类,因此您的设置不同寻常。 FXMLLoader解析FXML,看到fx:controller属性,并因此使用默认(无参数)构造函数实例化它。 (我在这里做一个假设,你不要在中的FXMLLoader上调用setControllersetControllerFactory。)因此,你有两个控制器实例:创建加载器的那个(从不调用initialize()方法的实例,以及@FXML注释字段永远不会被注入),并且由FXMLLoader(它被称为无参数构造函数,因此windowmenuCtrl字段未针对该实例初始化)创建。

您应该对此进行重构,以便创建FXMLLoader并将其传递给Window类以便在别处加载(即不需要实例化控制器),或者您应该明确地将控制器设置在FXMLLoader上。您可以分两步实现后者:

  1. 从MainMenu中删除fx:controller属性。FXML
  2. 明确设置控制器实例在renderMainMenu方法已经发布:

-

FXMLLoader loader = new FXMLLoader((getClass().getResource("MainMenu.fxml"))) ; 
loader.setController(this); 
window.loadFXML(loader); 
+0

您好,先生,真是太棒了,我对FX架构的工作原理完全错误,这清除了一切。 – jaxoncreed 2014-10-04 03:58:12

0

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

您可以从here

0

得到它你有两个构造函数。我的猜测是你正在加载一个FXML的地方,它会使用无参数构造函数实例化你的控制器。在这种情况下,menuCtrl没有被初始化。

如果你在FXML中实例化menuCtrl,那么在这个字段中添加一个@FXML注解。

+0

嗯,这很有道理,我稍后再试一试 – jaxoncreed 2014-10-03 16:44:28