2017-12-28 36 views
0

habe ich ein kleines Programm, um den Fehler zu reproduzieren ich in meinem aktuellen Projekt immer bin. Ich habe eine Controller-Klasse namens MainWindow.java, die für zwei .fxml Dateien verantwortlich ist: MainWindow.fxml und AnchorTest.fxml.

-Code für die Controller-Klasse:Erste Null-Zeiger-Ausnahme mit setCenter() -Methode in JavaFX mit Scene Builder 8.0

package projecterror.controller; 

import java.io.IOException; 

import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.Scene; 
import javafx.scene.control.Menu; 
import javafx.scene.control.MenuItem; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Screen; 
import javafx.stage.Stage; 

public class MainWindow extends Application { 

    private Stage primaryStage; 
    private BorderPane mainWindow; 

    @FXML 
    Menu menuFile, menuAnalysis; 
    @FXML 
    MenuItem menuNew; 


    @FXML 
    private void initialize() { 
     menuNew.setOnAction((event) -> { 
      try { 
       FXMLLoader loader = new FXMLLoader(); 
       loader.setLocation(getClass().getResource("../view/AnchorTest.fxml")); 
       AnchorPane anchorTest = (AnchorPane) loader.load(); 
       mainWindow.setCenter(anchorTest); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     }); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     this.primaryStage = primaryStage; 
     this.primaryStage.setTitle("Test Project"); 

     initMainWindow(); 

    } 

    public void initMainWindow() { 
     try { 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(getClass().getResource("../view/MainWindow.fxml")); 
      mainWindow = (BorderPane) loader.load(); 

      Scene scene = new Scene(mainWindow); 
      primaryStage.setScene(scene); 

      //Fullscreen 
      Screen screen = Screen.getPrimary(); 
      Rectangle2D bounds = screen.getVisualBounds(); 
      primaryStage.setX(bounds.getMinX()); 
      primaryStage.setY(bounds.getMinY()); 
      primaryStage.setWidth(bounds.getWidth()); 
      primaryStage.setHeight(bounds.getHeight()); 

      primaryStage.setResizable(false); 
      primaryStage.show(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

MainWindow.fxml ist ein BorderPane, die eine MenuBar auf top hat.

Code:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.Menu?> 
<?import javafx.scene.control.MenuBar?> 
<?import javafx.scene.control.MenuItem?> 
<?import javafx.scene.control.SeparatorMenuItem?> 
<?import javafx.scene.layout.BorderPane?> 

<BorderPane style="-fx-background-color: #DCDCDC;" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="projecterror.controller.MainWindow"> 
    <top> 
     <MenuBar BorderPane.alignment="CENTER"> 
     <menus> 
      <Menu fx:id="menuFile" mnemonicParsing="false" text="File"> 
      <items> 
        <Menu fx:id="menuAnalysis" mnemonicParsing="false" text="Analysis"> 
        <items> 
         <MenuItem fx:id="menuNew" mnemonicParsing="false" text="New" /> 
        </items> 
        </Menu> 
      </items> 
      </Menu> 
     </menus> 
     </MenuBar> 
    </top> 
</BorderPane> 


AnchorTest.fxml ist ein AnchorPane, die zwei AnchorPane als Kinder.

Code:

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.scene.layout.AnchorPane?> 

<AnchorPane xmlns:fx="http://javafx.com/fxml/1"> 
    <children> 
      <AnchorPane layoutX="6.0" layoutY="450.0" /> 
      <AnchorPane layoutX="6.0" layoutY="569.0" prefHeight="116.0" prefWidth="730.0"> 
        <Button layoutX="6.0" layoutY="26.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="102.0" text="Button 1" /> 
        <Button layoutX="115.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 2" /> 
        <Button layoutX="226.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 3" /> 
        <Button layoutX="115.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 4" /> 
        <Button layoutX="383.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 5" /> 
        <Button layoutX="491.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 6" /> 
        <Button layoutX="600.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 7" /> 
        <Button layoutX="491.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 8" /> 
        <Button layoutX="600.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 9" /> 
        <TextField alignment="TOP_CENTER" layoutX="341.0" layoutY="26.0" prefHeight="25.0" prefWidth="28.0" text="10" /> 
      </AnchorPane> 
     </children> 
</AnchorPane> 


Wenn auf MainWindow.fxml, nachdem ich auf das Menü klicken File > Analysis > New wird angenommen AnchorTest.fxml Inhalt in MainWindow.fxml Mitte zu platzieren. Allerdings bekomme ich folgenden Stack-Trace-Fehler:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException 
     at projecterror.controller.MainWindow.lambda$0(MainWindow.java:35) 
     at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
     at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
     at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
     at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
     at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
     at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
     at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) 
     at javafx.event.Event.fireEvent(Event.java:198) 
     at javafx.scene.control.MenuItem.fire(MenuItem.java:462) 
     at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405) 
     at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358) 
     at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) 
     at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) 
     at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
     at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
     at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
     at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
     at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
     at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
     at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
     at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
     at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
     at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
     at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
     at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
     at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
     at javafx.event.Event.fireEvent(Event.java:198) 
     at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) 
     at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) 
     at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) 
     at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) 
     at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380) 
     at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416) 
     at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
     at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415) 
     at com.sun.glass.ui.View.handleMouseEvent(View.java:555) 
     at com.sun.glass.ui.View.notifyMouse(View.java:937) 
     at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
     at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
     at java.lang.Thread.run(Thread.java:745) 

Die Linie, die die NPE erschlafft ist:

mainWindow.setCenter(anchorTest); 

ich weitere Fragen habe ähnlich wie diese aber meistens alle ihre Probleme wurden in Bezug auf Der Pfad der fxml-Dateien. Ich glaube fest daran, dass nicht das Problem ist, da in meinem eigentlichen Projekt, das ich den gleichen Typen des Weges für andere Ansichten verwenden und ich habe keine Probleme bisher.

Ich habe das Projekt here falls hochgeladen jemand will das Programm auszuführen.

Projektstruktur ist wie folgt:

Project structure

Vielen Dank im Voraus und jede Hilfe wäre sehr dankbar!

+0

Ich habe noch nie ein 'JavaFX Main' strukturiert auf diese Weise gesehen. – Sedrick

+0

Sie sollten auch die Struktur Ihres Projekts posten. – Sedrick

+1

'mainWindow' ist in der Steuerung nicht initialisiert; Es wird in der 'Application'-Instanz initialisiert, die beim Start der Anwendung erzeugt wird (die Instanz, an der 'start()' aufgerufen wird). Unter dem Strich sollten Sie die Anwendungsklasse nicht als Controller-Klasse verwenden. es ist zu verwirrend (und verstößt gegen alle möglichen grundlegenden OOP-Designprinzipien wie "Single Responsibility"). –

Antwort

2

Wenn Sie eine JavaFX-Anwendung starten, wird eine Instanz Ihrer Anwendungsklasse erstellt und (unter anderem) die start()-Methode in der Instanz Application für den FX-Anwendungs-Thread aufgerufen. Wenn Sie eine FXML-Datei laden, wird, wenn die FXML-Datei eine Controller-Klasse angibt, eine Instanz dieser Controller-Klasse erstellt, die @FXML -annotierten Felder werden in diese Instanz eingefügt, und die Methode initialize() wird aufgerufen. All dies geschieht während des Anrufs FXMLLoader.load().

Folglich in Ihrem Code, beenden Sie mit zwei verschiedenen Instanzen MainWindow auf. Die start() Verfahren wird auf eine Instanz aufgerufen wird, die die mainWindow Feld initialisiert und die initialize() Methode wird auf der anderen Instanz aufgerufen. Da mainWindow in dieser zweiten Instanz nie initialisiert wurde, erhalten Sie eine Nullzeigerausnahme, wenn Sie versuchen, es in der initialize()-Methode zu dereferenzieren.

Trennen Sie die Controller-Klasse von der Klasse Application. Die Application Klasse sollte nichts anderes tun, als den Lebenszyklus der Anwendung als Ganzes verwalten (in der Regel, sollte es den Code implementieren erforderlich, um die Anwendung zu starten):

package projecterror.controller; 

import java.io.IOException; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.Scene; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Screen; 
import javafx.stage.Stage; 

public class MainWindow extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     primaryStage.setTitle("Test Project"); 

     initMainWindow(primaryStage); 

    } 

    public void initMainWindow(Stage primaryStage) { 
     try { 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(getClass().getResource("../view/MainWindow.fxml")); 
      BorderPane mainWindow = loader.load(); 

      Scene scene = new Scene(mainWindow); 
      primaryStage.setScene(scene); 

      //Fullscreen 
      Screen screen = Screen.getPrimary(); 
      Rectangle2D bounds = screen.getVisualBounds(); 
      primaryStage.setX(bounds.getMinX()); 
      primaryStage.setY(bounds.getMinY()); 
      primaryStage.setWidth(bounds.getWidth()); 
      primaryStage.setHeight(bounds.getHeight()); 

      primaryStage.setResizable(false); 
      primaryStage.show(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 
package projecterror.controller; 

import java.io.IOException; 

import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.control.Menu; 
import javafx.scene.control.MenuItem; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.layout.BorderPane; 

public class MainWindowController { 

    @FXML 
    private BorderPane mainWindow; 

    @FXML 
    Menu menuFile, menuAnalysis; 
    @FXML 
    MenuItem menuNew; 


    @FXML 
    private void initialize() { 
     menuNew.setOnAction((event) -> { 
      try { 
       FXMLLoader loader = new FXMLLoader(); 
       loader.setLocation(getClass().getResource("../view/AnchorTest.fxml")); 
       AnchorPane anchorTest = (AnchorPane) loader.load(); 
       mainWindow.setCenter(anchorTest); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     }); 
    } 



} 

Um für den Controller Zugriff auf die BorderPane, müssen Sie es von der FXML injizieren (beachten Sie die Anmerkung im Controller-Code oben). Fügen Sie ein fx:id auf das Element in der FXML Datei:

<BorderPane style="-fx-background-color: #DCDCDC;" fx:id="mainWindow" 
    xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" 
    fx:controller="projecterror.controller.MainWindowController"> 
+0

Nur der Vollständigkeit halber glaube ich, dass Sie die 'private Stage primaryStage;' in der MainWindow-Klasse vergessen haben. Es funktioniert perfekt, danke für deine Erklärung. – leandrocoutom

+1

@leandrocoutom Eigentlich wollte ich es weglassen, da es nur in den 'start()' und 'initMainWindow()' Methoden benötigt wird, aber ich habe die Änderung nicht abgeschlossen. Lass mich reparieren ... –

Verwandte Themen