2016-12-05 7 views
1

Ich benutze JavaFX, um eine Ansicht von meinem Spiel zu zeigen.Nullpointer bei der Initialisierung der JavaFX-Ansicht

The View geladen wird, wenn ich die Methode in meiner MainApp Klasse aufrufen:

public class MainApp extends Application { 

    //fields 

    public MainApp() { 
     this.game = new Game(); 
    } 

    //lots of other methods 

    public void showGameView() { 
     try { 
      System.out.println(game.getPlayer().getCurrentRoom()); 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(MainApp.class.getResource("view/GameView.fxml")); 
      AnchorPane GameView = (AnchorPane) loader.load(); 
      rootLayout.setCenter(GameView); 
      GameViewController controller = loader.getController(); 
      controller.setMainApp(this); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public Game getGame() { 
     return game; 
    } 

Die Game Objekt speichert einige Informationen und Material. Der Controller sieht folgendermaßen aus:

public class GameViewController { 

    private MainApp mainApp; 

    @FXML 
    public void initialize() { 
     mainApp.getGame(). ... //do something else 
    } 

    public void setMainApp(MainApp mainApp) { 
     this.mainApp = mainApp; 
    } 

Ich habe es immer so gemacht. Wenn der Controller geladen wird, werden die MainApp Objekte in den Controller gesetzt und ich kann damit arbeiten. Aber jetzt bekomme ich einen Nullpointer, wenn jemand mainApp.get... ruft. Das Feld mainApp ist null. Ich weiß wirklich nicht, was der Deal hier ist, denn wie gesagt, es hat in anderen Projekten so funktioniert.

Antwort

2

Wirklich nur eine Erweiterung zu fabians Antwort. Ich stimme zu, dass Sie die Controller-Instanz selbst erstellen sollten (entfernen Sie die fx:controller in der FXML, wie er sagte). Es erlaubt Ihnen, Zeug als final zu deklarieren, was Sie sonst nicht können würden, und vermeidet, dass Sie viele Setter in Ihrer öffentlichen API haben müssen, die Sie sonst nicht benötigen würden.

könnten Sie wahrscheinlich viele Ihrer initialise Code in den Konstruktor bewegen. Normalerweise setze ich Code nur in initialise, wenn er direkt eines der JavaFX-Widgets verändert.

Es würde wie folgt aussehen:

public void showGameView() { 
    try { 
     System.out.println(game.getPlayer().getCurrentRoom()); 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(MainApp.class.getResource("view/GameView.fxml")); 
     loader.setController(new GameViewController(this)); 
     AnchorPane GameView = (AnchorPane) loader.load(); 
     rootLayout.setCenter(GameView); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

und

public class GameViewController { 

    private final MainApp mainApp; 

    public GameViewController(MainApp mainApp) 
    { 
     this.mainApp = mainApp; 
    } 

    @FXML 
    public void initialize() { 
     mainApp.getGame(). ... //do something else 
    } 
+0

Das sieht nach einer ziemlich guten und einfachen Lösung aus. Und ich denke, sein sauberer Stil als das, was ich zuerst in dem Kommentar zu den anderen Antworten dachte. Danke auch! – Master1114

3

initialize Die Verfahren der Controller-Klasse ist am Ende des FXMLLoader.load Methodenaufruf aufgerufen wird, das heißt, bevor Sie das tun

controller.setMainApp(this); 

die das mainApp Feld noch null enthält zu dieser Zeit bedeutet.

Sie müssen den Code bewegen dereferencing mainApp vom initialize Verfahren zur setMainApp Methode, erstellen Sie die Controller-Instanz mit initialisiert mainApp Eigenschaft selbst und gibt es an die FXMLLoader vor dem Laden (erfordert die Entfernung von fx:controller Attribute) oder eine Controller Fabrik mit um die Controller-Instanz zu initialisieren (was wahrscheinlich die komplizierteste der Optionen ist).

+0

Ok, so das Feld leer ist, weil das Feld gesetzt wird, nachdem die 'Initialisiere()' aufgerufen wird. Ich denke, nur eine andere 'init()' Methode in der 'setMainApp()' aufzurufen ist eine Art unrein, aber ich denke, ich muss es so nehmen. Danke – Master1114

+0

@ Master1114 Der üblicher Ansatz wäre zu nennen 'mainApp.getGame (...)' etc vom 'setMainApp (...)' Methode; Aber wenn Sie eine zusätzliche 'init()' Methode wünschen, gibt es nichts, was Sie davon abhält. –

Verwandte Themen