JAVAFX:控制器类中的字段值为';无法正确保存/更新listview时出现问题?

JAVAFX:控制器类中的字段值为';无法正确保存/更新listview时出现问题?,java,listview,javafx,scenebuilder,Java,Listview,Javafx,Scenebuilder,所以我用JavaFX制作了一个小程序来熟悉它 我很确定,我对javafx的工作原理有一些基本的了解,但这似乎让我难以理解,因为我遇到了一些无法找到解决方案的问题。尽管在谷歌上对它们进行了彻底的研究 目前我有一个使用eclipse和SceneBuilder1.1的设置(因为2.0给了我各种各样的麻烦) 我有一个非常简单的设置,其中有一个主应用程序,加载初始主应用程序窗口 public class Main extends Application { @Override

所以我用JavaFX制作了一个小程序来熟悉它

我很确定,我对javafx的工作原理有一些基本的了解,但这似乎让我难以理解,因为我遇到了一些无法找到解决方案的问题。尽管在谷歌上对它们进行了彻底的研究

目前我有一个使用eclipse和SceneBuilder1.1的设置(因为2.0给了我各种各样的麻烦)

我有一个非常简单的设置,其中有一个主应用程序,加载初始主应用程序窗口

public class Main extends Application {
        @Override 
        public void start(final Stage stage) throws Exception { 
           Parent root = FXMLLoader.load(getClass().getResource("/application/ApplicationWindow.fxml"));        
            Scene scene = new Scene(root);
            stage.getIcons().add(new Image("/application/bug3.png"));
            stage.setResizable(true);
            stage.setTitle("Simple Bugtracker");
            stage.setMinHeight(500);
            stage.setMinWidth(800);
            stage.setScene(scene);
            stage.show();
        }        

        public static void main(String[] args) { launch(args); } 
}
它似乎工作得很好。然后,我创建了一个控制器类,它包含正确的fx:id'etgui元素作为字段值,运行良好,我可以用java代码操作它们

到目前为止,我有两个问题

1) 当我从我的一个listview中删除某些内容时,我已经设法修复了更新问题,因此它通过添加if null场景立即将其从listview中删除。但是当我创建一个对象类型的新实例时,listview在我重新启动程序之前不会更新

2) 其次,我在控制器类中遇到了一个简单的int字段值的问题,我想在im调用的方法中使用它的当前值(在scenebuilder的按钮上设置),但它似乎总是坚持认为,即使该值设置正确,它仍然是在启动期间实例化时的原始值

这是我相当大的控制器类

public class MyController implements Initializable {

    // Logic related fields
    public ProjectList<Project> projectList = new ProjectList<Project>();
    public int currentProjectIndex = -1;
    public Bug currentBug;

    // Listview buffers
    public ObservableList<Project> projectsListBuffer = FXCollections.observableArrayList();
    public ObservableList<Bug> unsolvedListBuffer = FXCollections.observableArrayList();
    public ObservableList<Bug> solvedListBuffer = FXCollections.observableArrayList();

    // GUI related fields

    @FXML public ListView<Project> projectsListView;
    @FXML public ListView<Bug> unsolvedListView;
    @FXML public ListView<Bug> solvedListView;


    @FXML public TextArea topDisplayArea;
    @FXML public Button btnCreateProject;

    @FXML public TextField titleFieldCreateProject;
    @FXML public TextArea descriptionAreaCreateProject;

    @FXML public AnchorPane createProjectWindow;
    @FXML public AnchorPane projectsListViewAnchor;

    @FXML public Label projectTitleLabel;
    @FXML public Button createBugButton;

    @FXML public TextField titleFieldCreateBug;
    @FXML public TextArea descriptionAreaCreateBug;

    public Stage createProjectStage;
//  public Stage createBugStage;


    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        // load data from file system
        try {
            loadData();
        } catch (IOException e) {           
            e.printStackTrace();
        }
        // Instantiate gui field values
//      projectsListView = new ListView();
//      unsolvedListView = new ListView();
//      solvedListView = new ListView();
//
//
//      topDisplayArea = new TextArea();
//      btnCreateProject = new Button();
//
//      titleFieldCreateProject = new TextField();
//      descriptionAreaCreateProject = new TextArea();
//
//      createProjectWindow = new AnchorPane();
//      projectsListViewAnchor = new AnchorPane();
//
//      projectTitleLabel = new Label();
//      createBugButton = new Button();
//      
//      titleFieldCreateBug = new TextField();
//      descriptionAreaCreateBug = new TextArea();


        updateListBuffers();

        projectsListView.setPrefHeight( getScreenH() );
        projectsListView.setItems(projectsListBuffer);
        unsolvedListView.setPrefHeight( getScreenH() );
        unsolvedListView.setItems(unsolvedListBuffer);

        // settings on necessary gui items

        topDisplayArea.setPrefHeight( getScreenH() );
        topDisplayArea.setPrefWidth( getScreenW() );
        topDisplayArea.setEditable(false);
        topDisplayArea.setBackground(null); // something to be done here for transparent logo in background of all project descriptions etc.

        // ved dobbeltklik i projektlisten, vælg project og sæt titel
        projectsListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {

                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentProjectIndex = projectsListView.getSelectionModel().getSelectedIndex();
                    Project currentProject = projectList.get(projectsListView.getSelectionModel().getSelectedIndex());
                    projectTitleLabel.setText(currentProject.getTitle());
                    System.out.println( "Selected project:"+currentProject.getTitle());                 
                    solvedListView.setItems(unsolvedListBuffer);
                    for (Bug b : currentProject.solvedBugs) {
                        System.out.println(b.getTitle()+"\n"+b.getErrorDescription());
                    }
                    updateListBuffers();
                }
            }
        });

        // ved dobbeltklik i uløste bugs listen, sæt top display område
        unsolvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {
                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentBug = unsolvedListView.getSelectionModel().getSelectedItem();
                    topDisplayArea.setText(currentBug.getErrorDescription());
                }
            }
        });

        solvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {
                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentBug = solvedListView.getSelectionModel().getSelectedItem();
                    topDisplayArea.setText(currentBug.getErrorDescription());
                }
            }
        });

        // custom listview cell for the projects listview
        projectsListView.setCellFactory(new Callback<ListView<Project>, ListCell<Project>>() {
            @Override
            public ListCell<Project> call(ListView<Project> p) {

                ListCell<Project> cell = new ListCell<Project>() {
                    @Override
                    protected void updateItem(Project t, boolean bln) {

                        super.updateItem(t, bln);

                        if (t != null) {
                            // program a custom cell with several items in it
                            Text text = new Text();
                            Text text2 = new Text();
                            text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text.setText(t.getTitle());
                            text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text2.setText(t.getCreationDate().toLocaleString());
                            text.setFont(Font.font ("Verdana", 12));
                            text2.setFont(Font.font ("Verdana", 10));
                            text.setFill(Color.BLACK);
                            text2.setFill(Color.TEAL);
                            AnchorPane pane = new AnchorPane();     
                            pane.setPrefHeight(90);
                            pane.setPrefWidth(300);
                            ImageView imageView = new ImageView();
                            imageView.setImage(new Image("/application/project1.png"));
                            imageView.setFitHeight(60);
                            imageView.setFitWidth(60);
                            Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));

                            Button deleteButton = new Button("Delete");
                            deleteButton.setLayoutX(233);
                            deleteButton.setLayoutY(60);
                            text.setLayoutX(70);
                            text.setLayoutY(30);
                            text2.setLayoutX(70);
                            text2.setLayoutY(50);
                            pane.getChildren().addAll(imageView, text, text2, deleteButton);

                            // delete actionevent           
                            deleteButton.setOnAction(new EventHandler<ActionEvent>() {
                                @Override 
                                public void handle(ActionEvent e) { 

                                    Alert alert = new Alert(AlertType.CONFIRMATION);
                                    alert.setTitle("Confirm deletion");
                                    alert.setHeaderText("Are you sure you want to delete this project?");
                                    Optional<ButtonType> result = alert.showAndWait();
                                    if (result.get() == ButtonType.OK){
                                        int selIndex = projectsListView.getSelectionModel().getSelectedIndex();
                                        if (selIndex>-1) {
                                            projectsListBuffer.remove(selIndex);
                                            projectList.remove(selIndex);                           
                                            projectsListView.setItems(projectsListBuffer);
                                            projectList.save();
                                        }

                                    } else {
                                        System.out.println("DENIED!!");
                                    }                                                               
                                }
                            });

                            setPrefWidth(0);
                            setGraphic(pane);
                        } else {
                            setText(null);
                            setGraphic(null);
                        }
                    }
                };
                return cell;
            }
        });

        // custom listview cell for the unsolved bugs listview
        unsolvedListView.setCellFactory(new Callback<ListView<Bug>, ListCell<Bug>>() {
            @Override
            public ListCell<Bug> call(ListView<Bug> p) {

                ListCell<Bug> cell = new ListCell<Bug>() {
                    @Override
                    protected void updateItem(Bug t, boolean bln) {
                        super.updateItem(t, bln);

                        if (t != null) {
                            // program a custom cell with several items in it
                            Text text = new Text();
                            Text text2 = new Text();
                            text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text.setText(t.getTitle());
                            text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text2.setText(t.getCreationDate().toLocaleString());
                            text.setFont(Font.font ("Verdana", 12));
                            text2.setFont(Font.font ("Verdana", 10));
                            text.setFill(Color.BLACK);
                            text2.setFill(Color.TEAL);
                            AnchorPane pane = new AnchorPane();     
                            pane.setPrefHeight(90);
                            pane.setPrefWidth(300);
                            ImageView imageView = new ImageView();
                            imageView.setImage(new Image("/application/bug3.png"));
                            imageView.setFitHeight(60);
                            imageView.setFitWidth(60);
                            Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));

                            Button selectButton = new Button("Select"); 
                            Button deleteButton = new Button("Delete");
                            selectButton.setLayoutX(233);
                            selectButton.setLayoutY(60);
                            deleteButton.setLayoutX(180);
                            deleteButton.setLayoutY(60);
                            text.setLayoutX(70);
                            text.setLayoutY(30);
                            text2.setLayoutX(70);
                            text2.setLayoutY(50);
                            pane.getChildren().addAll(imageView, text, text2);

                            deleteButton.setOnAction(new EventHandler<ActionEvent>() {
                                @Override 
                                public void handle(ActionEvent e) {                          
                                    projectsListBuffer.remove(projectsListView.getSelectionModel().getSelectedIndex());
                                    projectList.remove(projectsListView.getSelectionModel().getSelectedIndex());                            
                                    projectsListView.setItems(projectsListBuffer);
                                    projectList.save();
                                }
                            });

                            setPrefWidth(0);
                            setGraphic(pane);
                        } else {
                            setText(null);
                            setGraphic(null);
                        }
                    }
                };

                return cell;
            }
        });


    }

    // loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
    public void showCreateProjectWindow() {
        try {
            Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateProjectWindow.fxml"));    
            createProjectStage = new Stage();
            Scene scene = new Scene(root1);         
            createProjectStage.setScene(scene);  
            createProjectStage.setMinWidth(374);
            createProjectStage.setMinHeight(416);
            createProjectStage.setResizable(false);
            createProjectStage.show();          
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // actionevent method that creates a new project   MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
    public void createProject() {
        String title = titleFieldCreateProject.getText();
        String description = descriptionAreaCreateProject.getText();
        Project project = new Project(title, description, new Date());
        projectList.add(project);
        projectsListBuffer.add(project);
        projectList.save();
        updateListBuffers();
        projectsListView.setItems(projectsListBuffer);      

    }

    // loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
    public void showCreateBugWindow() {
        try {
            Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateBugWindow.fxml"));    
            createProjectStage = new Stage();
            Scene scene = new Scene(root1);         
            createProjectStage.setScene(scene);  
            createProjectStage.setMinWidth(374);
            createProjectStage.setMinHeight(416);
            createProjectStage.setResizable(false);
            createProjectStage.show();          
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // actionevent method that creates a new bug   MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
        public void createBug() {
            if (currentProjectIndex >-1) {
                String title = titleFieldCreateBug.getText();
                String description = descriptionAreaCreateBug.getText();
                System.out.println(title+"\n"+description);
                Bug bug = new Bug(title, description, new Date());
                projectList.get(currentProjectIndex).unsolvedBugs.add(bug);
                unsolvedListBuffer.add(bug);
                projectList.save();         
                updateListBuffers();
            } else {
                System.out.println("Failed creation.");
            }
        }

    // load, clear and reload buffers
    public void updateListBuffers() {
        if (currentProjectIndex>-1) {
            unsolvedListBuffer.clear();     
            for (int i=0; i<projectList.get(currentProjectIndex).unsolvedBugs.size(); i++) {            
                unsolvedListBuffer.add( projectList.get(currentProjectIndex).unsolvedBugs.get(i) );         
            }
            solvedListBuffer.clear();           
            for (int i=0; i<projectList.get(currentProjectIndex).solvedBugs.size(); i++) {          
                solvedListBuffer.add( projectList.get(currentProjectIndex).solvedBugs.get(i) );         
            }
//          unsolvedListView.setItems(null);
//          solvedListView.setItems(null);
            unsolvedListView.setItems(unsolvedListBuffer);
            solvedListView.setItems(solvedListBuffer);
        }   
        projectsListBuffer.clear();     
        for (int i=0; i<projectList.size(); i++) {          
            projectsListBuffer.add( projectList.get(i) );           
        }   
//      projectsListView.setItems(null);
        projectsListView.setItems(projectsListBuffer);

    }

    // file system related methods

    public void loadData() throws IOException {
        File fil = new File("Project_Data.dat");
        if ( !fil.exists() ) {
            fil.createNewFile();
            projectList = new ProjectList<Project>();
            projectList.save();
        } else {
            projectList = ProjectList.load();
        }
    }

    // practical methods

    public double getScreenH() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return screenSize.getHeight();
    }

    public double getScreenW() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return screenSize.getWidth();
    }

}

您的问题几乎不可能像您所拥有的那样得到回答,因为您拥有的代码远远多于重现问题所需的代码,但您没有包含关键元素(如FXML文件)。最好从头开始创建一个小的、简单的、完整的示例来演示问题,而不是发布一个完整的控制器类

以下是一些适用于您所看到的问题的一般情况

下面是调用
fxmloader
load(…)
方法时发生的基本过程:

  • fxmloader
    加载FXML文件
  • 如果根元素具有
    fx:controller
    属性,并且没有 控制器之前已设置,加载程序将字符串转换为
    类。如果在加载器上设置了
    controllerFactory
    ,则将
    传递给控制器工厂的
    调用(…)
    方法后,将检索构造函数。否则,将通过指定的类“无参数构造函数”实例化控制器。(如果之前已设置控制器,则加载过程将终止,并出现异常。)
  • 加载程序解析FXML文件,创建指定的对象,并根据FXML结构将它们传递给彼此的各种集合方法。当创建了一个具有
    fx:id
    属性的对象,并且(通过任何方式)创建了一个控制器时,控制器中带有与
    fx:id
    值同名的
    @FXML
    注释字段(如果存在)将初始化为该对象
  • 如果已创建控制器,并且该控制器具有
    initialize()
    方法,则调用
    initialize()
    方法
  • load方法通过返回对根元素对应的对象的引用来完成
  • 从编码的角度来看,这会带来一些后果:

    声明和初始化带注释的字段,例如:

    @FXML
    private Label myLabel = new Label();
    
    它总是多余的。如果正确设置了
    fx:id
    ,则在加载过程中将为
    myLabel
    重新分配一个新值,并丢弃原始初始化值。更糟糕的是,如果未正确设置
    fx:id
    ,则使用
    myLabel
    所做的任何操作都将应用于不属于场景图一部分的标签,因此您将获得难以调试的意外结果(基本上,操作将成功,但在UI中没有可见效果)。如果不初始化字段,则如果未正确设置
    fx:id
    ,它将立即失败,出现
    NullPointerException
    ,然后可以轻松调试

    类似地,在
    initialize()
    方法中重新初始化
    @FXML
    -注释字段总是一场灾难:

    @FXML
    private Label myLabel ;
    
    public void initialize() {
        myLabel = new Label(...);
        // ...
    }
    
    在这种情况下,
    myLabel
    首先由FXML加载程序初始化,但是当调用
    initialize()
    方法时,它会被不属于场景图的其他标签替换。因此,对
    myLabel
    的操作将成功,但不会在UI中产生可见的效果

    其次,在“标准”控制器设置中,您不在
    fxmloader
    上调用
    setController
    setControllerFactory
    ,而是通过
    fx:controller
    属性指定控制器类,每个
    fxmloader
    创建相应控制器类的一个实例。从堆栈跟踪来看,它看起来像是
    ApplicationWindow.fxml
    CreateProjectWindow.fxml
    使用相同的控制器类。这总是一个坏主意:当共享控制器类的每个实例与特定FXML文件定义的FXML元素相对应时,它们只会初始化带有
    @FXML
    -注释的字段。显然,他们不会知道彼此的数据。您应该为每个FXML文件创建不同的控制器类。如果他们需要共享数据,请使用中概述的技术。通常,您可以通过在一个控制器中创建和公开一个可观察属性,并从另一个控制器中观察它来管理这一点,如下例所示

    这里有一个简单的例子,我猜你的例子有一些相同的结构。这可能有助于研究和理解这一点。这里的所有内容都放在一个名为“application”的包中(包括FXML文件)

    数据模型类别:Pers
    @FXML
    private Label myLabel ;
    
    public void initialize() {
        myLabel = new Label(...);
        // ...
    }
    
    package application;
    
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    
    public class Person {
        private final StringProperty firstName = new SimpleStringProperty();
        private final StringProperty lastName = new SimpleStringProperty();
    
        public Person(String firstName, String lastName) {
            setFirstName(firstName);
            setLastName(lastName);
        }
    
        public final StringProperty firstNameProperty() {
            return this.firstName;
        }
    
        public final String getFirstName() {
            return this.firstNameProperty().get();
        }
    
        public final void setFirstName(final String firstName) {
            this.firstNameProperty().set(firstName);
        }
    
        public final StringProperty lastNameProperty() {
            return this.lastName;
        }
    
        public final String getLastName() {
            return this.lastNameProperty().get();
        }
    
        public final void setLastName(final String lastName) {
            this.lastNameProperty().set(lastName);
        }
    
        @Override
        public String toString() {
            return getFirstName() +" "+getLastName();
        }
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.BorderPane?>
    <?import javafx.scene.control.ListView?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.Button?>
    
    <BorderPane xmlns:fx="http://javafx.com/fxml/1"
        fx:controller="application.PersonListController">
        <center>
        <ListView fx:id="personList" />
    </center>
        <bottom>
            <HBox spacing="5">
                <padding>
                    <Insets top="10" bottom="10" left="10" right="10" />
                </padding>
                <Button text="New..." onAction="#newPerson" />
                <Button text="Edit..." onAction="#editPerson" fx:id="editButton" />
            </HBox>
        </bottom>
    </BorderPane>
    
    package application;
    
    import javafx.beans.Observable;
    import javafx.beans.binding.Bindings;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.ListView;
    import javafx.stage.Stage;
    
    
    public class PersonListController {
        @FXML
        private ListView<Person> personList ;
        @FXML
        private Button editButton ;
    
        public void initialize() {
    
            // list created so it fires updates if either the firstName or lastName change:
            ObservableList<Person> people = FXCollections.observableArrayList(person -> 
                new Observable[] {person.firstNameProperty(), person.lastNameProperty()});
    
            people.addAll(new Person("Jacob", "Smith"),
                    new Person("Isabella", "Johnson"),
                    new Person("Ethan", "Williams"),
                    new Person("Emma", "Jones"),
                    new Person("Michael", "Johnson"));
            personList.setItems(people);
    
            editButton.disableProperty().bind(
                    Bindings.isNull(personList.getSelectionModel().selectedItemProperty()));
        }
    
        @FXML
        private void newPerson() throws Exception {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("PersonEditor.fxml"));
            Parent root = loader.load();
    
            PersonEditorController controller = loader.getController();
            controller.personProperty().addListener((obs, oldPerson, newPerson) -> {
                if (newPerson != null) {
                    personList.getItems().add(newPerson);
                }
            });
    
            showEditorWindow(root);
        }
    
    
        @FXML
        private void editPerson() throws Exception {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("PersonEditor.fxml"));
            Parent root = loader.load();
    
            PersonEditorController controller = loader.getController();
            controller.setPerson(personList.getSelectionModel().getSelectedItem());
    
            showEditorWindow(root);
        }
    
        private void showEditorWindow(Parent root) {
            Scene scene = new Scene(root, 350, 200);
            Stage stage = new Stage();
            stage.initOwner(personList.getScene().getWindow());
            stage.setScene(scene);
            stage.show();
        }
    
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.GridPane?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.Button?>
    
    <GridPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PersonEditorController">
        <Label text="First Name:" GridPane.columnIndex="0"
            GridPane.rowIndex="0" />
        <Label text="Last Name:" GridPane.columnIndex="0"
            GridPane.rowIndex="1" />
        <TextField fx:id="firstNameTF" GridPane.columnIndex="1"
            GridPane.rowIndex="0" />
        <TextField fx:id="lastNameTF" GridPane.columnIndex="1"
            GridPane.rowIndex="1" />
        <HBox GridPane.columnIndex="0" GridPane.rowIndex="2"
            GridPane.columnSpan="2" spacing="5">
            <padding>
                <Insets top="5" bottom="5" left="5" right="5" />
            </padding>
            <Button text="OK" onAction="#submit" />
            <Button text="Cancel" onAction="#cancel" />
        </HBox>
    </GridPane>
    
    package application;
    
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.fxml.FXML;
    import javafx.scene.control.TextField;
    
    public class PersonEditorController {
        @FXML
        private TextField firstNameTF ;
        @FXML
        private TextField lastNameTF ;
    
        private final ObjectProperty<Person> person = new SimpleObjectProperty<>();
    
        public ObjectProperty<Person> personProperty() {
            return person;
        }
        public final Person getPerson() {
            return personProperty().get();
        }
        public final void setPerson(Person person) {
            personProperty().set(person);
        }
    
        public void initialize() {
            personProperty().addListener((obs, oldPerson, newPerson) -> {
                if (newPerson != null) {
                    firstNameTF.setText(newPerson.getFirstName());
                    lastNameTF.setText(newPerson.getLastName());
                }
            });
        }
    
        @FXML
        private void submit() {
            if (person.get() == null) {
                person.set(new Person(firstNameTF.getText(), lastNameTF.getText()));
            } else {
                person.get().setFirstName(firstNameTF.getText());
                person.get().setLastName(lastNameTF.getText());
            }
            close();
        }
    
        @FXML
        private void cancel() {
            close();
        }
    
        private void close() {
            firstNameTF.getScene().getWindow().hide();
        }
    }
    
    package application;
    
    import javafx.application.Application;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.layout.BorderPane;
    import javafx.fxml.FXMLLoader;
    
    
    public class Main extends Application {
        @Override
        public void start(Stage primaryStage) {
            try {
                BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("PersonList.fxml"));
                Scene scene = new Scene(root,400,400);
                primaryStage.setScene(scene);
                primaryStage.show();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }