javafx:尝试加载新舞台时发生NullPointerException

时间:2019-02-06 16:40:35

标签: java javafx nullpointerexception

我一直在遵循有关javafx的教程,该教程由一个简单的地址簿组成,一切正常,直到我尝试创建一个新阶段,在该阶段中,我必须填充文本字段以创建新Person或编辑现有文本人,但是当我单击添加按钮或编辑按钮时,新的舞台没有出现,并且我收到了NullPointerException:

java.lang.NullPointerException
at com.nouh.address.view.PersonEditDialogController.setPerson(PersonEditDialogController.java:72)
at com.nouh.address.MainApp.showPersonEditDialog(MainApp.java:144)
at com.nouh.address.view.PersonOverviewController.handleAdd(PersonOverviewController.java:159)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1784)
at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8863)
at javafx.controls/javafx.scene.control.Button.fire(Button.java:200)
at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3876)
at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1300(Scene.java:3604)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1874)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2613)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
at javafx.graphics/com.sun.glass.ui.mac.MacView.notifyMouse(MacView.java:127)

**我正在使用的类是:**

    package com.nouh.address;
    import com.nouh.address.model.Person;
    import com.nouh.address.view.PersonEditDialogController;
    import com.nouh.address.view.PersonOverviewController;
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Modality;

    import javafx.stage.Stage;
    import java.io.IOException;
    public class MainApp extends Application {

    private Stage primaryStage;
    private BorderPane rootLayout;

    /**
     * The data as an observable list of Persons.
     */
    private ObservableList<Person> personData = 
    FXCollections.observableArrayList();

    //constructor to add some simple data to the observable

    public MainApp(){

        personData.add(new Person("Hans", "Muster"));
        ....  //some dummy data

    }

    public static void main(String []args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage){

        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("Address App");

        initRootLayout();

        showPersonOverview();
    }

    private void initRootLayout(){
        try{
            //1- load the fxml file :
            FXMLLoader loader = new FXMLLoader();
            //2- set the relative path to the fxml file we want to load :
            loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
            //3-load the UI :
            this.rootLayout = (BorderPane)loader.load();
            //4- create a scene and then set the UI elements we've loaded on the that scene
            Scene scene = new Scene(this.rootLayout);
            //5- put the scene inside the window
            this.primaryStage.setScene(scene);

            //6. show the stage
            this.primaryStage.show();

        }catch (IOException fxmlLoaderError){
            System.out.println("ioE : fxml \n"+fxmlLoaderError.getMessage());
        }
    }

    private void showPersonOverview(){
       try {
           // Load person overview.
           FXMLLoader loader = new FXMLLoader();
           loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));

           AnchorPane pane = (AnchorPane)loader.load();
           this.rootLayout.setCenter(pane);

           // Give the controller access to the main app.
           PersonOverviewController controller = loader.getController();
           controller.setMainApp(this);

       }catch (IOException fxmlLoaderError){
           System.out.println("ioE : fxml 
           \n"+fxmlLoaderError.getMessage());
       }
    }

    public Stage getPrimaryStage() {
        return primaryStage;
    }

    public ObservableList<Person> getPersonData() {
        return personData;
    }

    public void setPersonData(ObservableList<Person> personData) {
        this.personData = personData;
    }

    /**
     * Opens a dialog to edit details for the specified person. If the user
     * clicks OK, the changes are saved into the provided person object and true
     * is returned.
     *
     * @param person the person object to be edited
     * @return true if the user clicked OK, false otherwise.
     */
    public boolean showPersonEditDialog(Person person){
        try {
            //load
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("view/PersonEditDialog.fxml"));
            AnchorPane editRootLayout = (AnchorPane)loader.load();

            //create the stage;
            Stage dialogStage = new Stage();
            dialogStage.setTitle("Edit Person");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);

            Scene scene = new Scene(editRootLayout);
            dialogStage.setScene(scene);

            // Set the person into the controller.
            PersonEditDialogController controller = new PersonEditDialogController();
            controller.setDialogStage(dialogStage);
            controller.setPerson(person);

            //show and wait :
            dialogStage.showAndWait();
            return controller.isOkClicked();

        }catch (IOException e){
            System.out.println("can't load the edit dialog");
            return false;
        }catch (NullPointerException e){
            System.out.println(e.getMessage()+" : here is the error");
            e.printStackTrace();
            return false;
        }
    }
}

模型类:

package com.nouh.address.model;

import javafx.beans.property.*;

import java.time.LocalDate;

public class Person {

    private final StringProperty firstname;
    private final StringProperty lastname;
    private final StringProperty city;
    private final StringProperty street;
    private final StringProperty email;
    private final IntegerProperty postalCode;
    private final ObjectProperty<LocalDate> birthdate;

    public Person(String firstname,String lastname){

        this.firstname = new SimpleStringProperty(firstname);
        this.lastname = new SimpleStringProperty(lastname);

        //default data
        this.street = new SimpleStringProperty("some street");
        this.city = new SimpleStringProperty("some beautiful city");
        this.email = new SimpleStringProperty("myemail@google.com");
        this.postalCode = new SimpleIntegerProperty(123456789);
        this.birthdate = new SimpleObjectProperty<LocalDate>(LocalDate.of(2000,12,12));

    }

    public Person(){
        this("","");
    }

   .....//getters and setters around here

    public void setBirthdate(LocalDate birthdate) {
        this.birthdate.set(birthdate);
    }
}

控制者: PersonOverviewController:

package com.nouh.address.view;

import com.nouh.address.MainApp;
import com.nouh.address.model.Person;
import com.nouh.address.util.DateUtil;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.*;

import javafx.scene.control.Alert.AlertType;

public class PersonOverviewController {

    @FXML
    private TableView<Person> personTable;
    @FXML
    private TableColumn<Person,String> firstname_col;
    @FXML
    private TableColumn<Person,String> lastname_col;

    @FXML
    private Label firstname;

    @FXML
    private Label lastname;

...
    @FXML
    private Button add;

    @FXML
    private Button edit;

    @FXML
    private Button delete;

    //reference to the main app
    private MainApp mainApp;

    /**
     * The constructor.
     * The constructor is called before the initialize() method.
     */
    public PersonOverviewController(){

    }

    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    @FXML
    private void initialize(){
        //Initialize the person table with the two columns.
        this.firstname_col.setCellValueFactory(cellData-> cellData.getValue().firstnameProperty());
        this.lastname_col.setCellValueFactory(cellData-> cellData.getValue().lastnameProperty());

        //clear the person Details :
        clearFields();

        //add a change Listener : Listen for selection changes and show the person details when changed.
        personTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {
            @Override
            public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
                showPersonDetails(newValue);
            }
        });

        /*
        this code is equivalent  :
        personTable.getSelectionModel().selectedItemProperty().addListener(
                (observable , oldValue , newValue) -> showPersonDetails(newValue)
                );
         */
    }

    /**
     * Is called by the main application to give a reference back to itself.
     *
     * @param mainApp
     */
    public void setMainApp(MainApp mainApp){
        this.mainApp = mainApp;

        //add observable liste to the table of person :
        this.personTable.setItems(mainApp.getPersonData());
    }

    /**
     * Fills all text fields to show details about the person.
     * If the specified person is null, all text fields are cleared.
     *
     * @param person the person or null
     */

    private void showPersonDetails(Person person){
        if(person != null){

            firstname.setText(person.getFirstname());
            lastname.setText(person.getLastname());
            city.setText(person.getCity());
            street.setText(person.getCity());
            postalcode.setText(Integer.toString(person.getPostalCode()));

            // TODO: We need a way to convert the birthday into a String!
            birthdate.setText(DateUtil.format(person.getBirthdate()));
        }else {
            clearFields();
        }
    }

    private void clearFields(){
        firstname.setText("");
        lastname.setText("");
        street.setText("");
        city.setText("");
        birthdate.setText("");
        postalcode.setText("");
        email.setText("");
    }

    /**
     * Called when the user clicks on the delete button.
     */
    @FXML
    private void handleDeletePerson(){
        int indxOfSelectedPerson = personTable.getSelectionModel().getSelectedIndex();
        if(indxOfSelectedPerson >= 0){
            personTable.getItems().remove(indxOfSelectedPerson);
            refresh();
        }else {
            showError("");
        }

    }

    /**
     * Called when the user clicks the new button. Opens a dialog to edit
     * details for a new person.
     */
    @FXML
    private void handleAdd(){
        Person tempPerson = new Person();
        boolean okClicked = mainApp.showPersonEditDialog(tempPerson);
        if(okClicked){
            mainApp.getPersonData().add(tempPerson);
        }
    }

    /**
     * Called when the user clicks the edit button. Opens a dialog to edit
     * details for the selected person.
     */
    @FXML
    private void handleEditPerson(){
        Person selectedPerson = personTable.getSelectionModel().getSelectedItem();

        if(selectedPerson != null){
            boolean okClicked =  mainApp.showPersonEditDialog(selectedPerson);
            if(okClicked){
               showPersonDetails(selectedPerson);
            }
        }else {
            showError("please select a person to be edited");
        }
    }

    private void refresh(){
        personTable.getSelectionModel().clearSelection();
    }

    private void showError(String error){
        Alert alert = new Alert(AlertType.WARNING);

        alert.initOwner(mainApp.getPrimaryStage());
        alert.setTitle("No Selection");
        alert.setHeaderText("No Pesron Selected");
        alert.setContentText("please selecet a person from the table to delete"+error);

        alert.showAndWait();
    }
}

PersonEditDialogController:

 package com.nouh.address.view;

import com.nouh.address.model.Person;
import com.nouh.address.util.DateUtil;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.control.Alert.AlertType;

public class PersonEditDialogController {

    @FXML
    private TextField firstname_txt;

    @FXML
    private TextField lastname_txt;

    @FXML
    private TextField birthdate_txt;

    @FXML
    private TextField city_txt;

    @FXML
    private TextField street_txt;

    @FXML
    private TextField postalcode_txt;

    @FXML
    private Button cancel_btn;

    @FXML
    private Button ok_btn;


    private Stage dialogStage;
    private Person person;
    private boolean OkClicked = false;


    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */

    @FXML
    private void initialize(){

    }

    /**
     * Sets the stage of this dialog.
     *
     * @param dialogStage
     */
    public void setDialogStage(Stage dialogStage){
        this.dialogStage = dialogStage;
    }

    /**
     * Sets the person to be edited in the dialog.
     *
     * @param person
     */

    public void setPerson(Person person) {
        this.person = person;
        if(person != null) {
            firstname_txt.setText(this.person.getFirstname());
            lastname_txt.setText(person.getLastname());
            birthdate_txt.setText(DateUtil.format(person.getBirthdate()));
            birthdate_txt.setPromptText("dd.mm.yy");
            street_txt.setText(person.getStreet());
            city_txt.setText(person.getCity());
            postalcode_txt.setText(Integer.toString(person.getPostalCode()));
        }
    }

    public boolean isOkClicked() {
        return OkClicked;
    }

    @FXML
    private void handleOK(){
        if(isInputValid()){
            person.setFirstname(firstname_txt.getText());
            person.setLastname(lastname_txt.getText());
            person.setCity(city_txt.getText());
            person.setStreet(street_txt.getText());
            person.setPostalCode(Integer.parseInt(postalcode_txt.getText()));
            person.setBirthdate(DateUtil.parse(birthdate_txt.getText()));//look if it is a valid date?

            OkClicked = true;
            dialogStage.close();
        }
    }

    @FXML
    private void handleCancel(){
        this.dialogStage.close();
    }

    private boolean isInputValid(){
        String errorMessage = "";
        if(firstname_txt.getText() == null || firstname_txt.getText().length() == 0){
            errorMessage += "firstname can't be empty\n";
        }
        if(lastname_txt.getText() == null || lastname_txt.getText().length() == 0){
            errorMessage += "lastname can't be empty\n";
        }
        if(city_txt.getText() == null || city_txt.getText().length() == 0){
            errorMessage += "city can't be empty\n";
        }
        if(street_txt.getText() == null || street_txt.getText().length() == 0){
            errorMessage += "street can't be empty\n";
        }
        if(postalcode_txt.getText() == null || postalcode_txt.getText().length() == 0){
            errorMessage += "postal code can't be empty\n";
            return false;
        }else {
            try {
                int postal = Integer.parseInt(postalcode_txt.getText());
            }catch (NumberFormatException e){
               errorMessage += "postal code must be a positive number ";
            }
        }
        if(birthdate_txt.getText() == null || birthdate_txt.getText().length() == 0){
            errorMessage += "birthdate can't be empty\n";
        }else {
            if(!DateUtil.validDate(birthdate_txt.getText())){
                errorMessage += "birthdate incorrect\n";
            }
        }

        if(errorMessage.length() == 0)
            return true;

        showError(errorMessage);
        return false;
    }

    private void showError(String error){

        Alert alert = new Alert(AlertType.WARNING);
        alert.initOwner(this.dialogStage);

        alert.setTitle("invalid input");
        alert.setHeaderText("Please correct the invalid fields");
        alert.setContentText(error);

        alert.showAndWait();
    }
}

还有一个帮助器类:

package com.nouh.address.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class DateUtil {
    /** The date pattern that is used for conversion. Change as you wish. */
    private static final String DATE_PATTERN = "DD.MM.YYYY";

    //the date formatter
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_PATTERN);

    /**
     * Returns the given date as a well formatted String. The above defined
     * {@link DateUtil#DATE_PATTERN} is used.
     *
     * @param date the date to be returned as a string
     * @return formatted string
     */

    public static String format(LocalDate date){
        if(date == null){
            return null;
        }
        return DATE_FORMATTER.format(date);
    }

    /**
     * Converts a String in the format of the defined {@link DateUtil#DATE_PATTERN}
     * to a {@link LocalDate} object.
     *
     * Returns null if the String could not be converted.
     *
     * @param dateString the date as String
     * @return the date object or null if it could not be converted
     */
    public static LocalDate parse(String dateString){
        try {
            return DATE_FORMATTER.parse(dateString, LocalDate::from);
        }catch (DateTimeParseException e){
            return null;
        }
    }

    /**
     * Checks the String whether it is a valid date.
     *
     * @param dateString
     * @return true if the String is a valid date
     */
    public static boolean validDate(String dateString){
        //parse and the check the values
         return DateUtil.parse(dateString) != null;
            //LocalDate date = DateUtil.parse(dateString);
           // if( (date.getDayOfMonth() > 31) || (date.getDayOfMonth() < 0) || (date.getMonthValue()>12) || (date.getMonthValue() < 0))
                //return false;
           // return true;

    }
}

我怀疑问题出在 MainApp.java

public boolean showPersonEditDialog(Person person){
    try {
        //load
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(MainApp.class.getResource("view/PersonEditDialog.fxml"));
        AnchorPane editRootLayout = (AnchorPane)loader.load();

        //create the stage;
        Stage dialogStage = new Stage();
        dialogStage.setTitle("Edit Person");
        dialogStage.initModality(Modality.WINDOW_MODAL);
        dialogStage.initOwner(primaryStage);

        Scene scene = new Scene(editRootLayout);
        dialogStage.setScene(scene);

        // Set the person into the controller.
        PersonEditDialogController controller = new PersonEditDialogController();
        controller.setDialogStage(dialogStage);
        controller.setPerson(person);

        //show and wait :
        dialogStage.showAndWait();
        return controller.isOkClicked();

    }catch (IOException e){
        System.out.println("can't load the edit dialog");
        return false;
    }catch (NullPointerException e){
        System.out.println(e.getMessage()+" : here is the error");
        e.printStackTrace();
        return false;
    }
}

但我无法弄清楚,主要阶段和PersonOverView加载并正确显示,并且删除一个人也很好

0 个答案:

没有答案