2014-10-03 71 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