JavaFX - 将TableView选择中的数据填充到对话框中

时间:2018-02-02 10:41:44

标签: javafx dialog tableview populate

我正在学习从TableView的选定行获取数据,并使用该数据预填充对话框。无论我在加载对话框时做什么,我在Controller.java中得到NullPointerException - > showEditContactDialog() - > editController.setItem(item))。不知怎的,我无法将选定的数据传递给另一个类,并通过对话框显示它。感谢有人指出我正确的方向。这是代码:

Main.java:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import sample.datamodel.ContactData;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
        primaryStage.setTitle("Address Book");
        primaryStage.setScene(new Scene(root, 1280, 500));
        primaryStage.show();            
    }

    @Override
    public void stop(){
             ContactData.getInstance().saveContacts();
    }
}

Controller.java:

package sample;

    @FXML
    private TableView<Contact> tableView;   

    @FXML
    private BorderPane mainBorderPane;

    private Contact item;

    public Controller() {
    }

    @FXML
    public TableView<Contact> getTableView() {
        return tableView;
    }

    @FXML
    public void initialize(){
        loadContacts();
        tableView.setOnMouseClicked((MouseEvent event) -> {
                    if (event.getClickCount() > 0) {
                        item = tableView.getSelectionModel().getSelectedItem(); // *** get selection from TableView ***

                    }
                });
    }

    @FXML
    public void handleExit(){
        ContactData.getInstance().saveContacts();
        Platform.exit();
    }

    public void saveContacts() {
        ContactData.getInstance().saveContacts();
    }

    public void loadContacts() {
        ContactData.getInstance().loadContacts(); 
        tableView.setItems(ContactData.getInstance().getContacts()); 
    }

    public void deleteContact(){
        ContactData.getInstance().deleteContact(item);
    }

    public void showAddContactDialog(ActionEvent event) throws IOException {
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.initOwner(mainBorderPane.getScene().getWindow());
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("addContact.fxml"));
        try{
            dialog.getDialogPane().setContent(fxmlLoader.load());
           }catch(IOException e){
            System.out.println("Couldn't load the dialog");
            e.printStackTrace();
            return;
        }
        Optional<ButtonType> result = dialog.showAndWait();
        if(result.isPresent()){
           Dialog controller = fxmlLoader.getController();
        }
    }

    public void showEditContactDialog() throws Exception {
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.initOwner(mainBorderPane.getScene().getWindow());
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("editContact.fxml"));
        EditContactController editController = fxmlLoader.<EditContactController>getController();
        editController.setItem(item); // ****** trying to pass "item" but get NullPointerException *********   
        try{
            dialog.getDialogPane().setContent(fxmlLoader.load()); 
        } catch (IOException e) {
            System.out.println("Couldn't load the dialog");
            e.printStackTrace();
            return;
        }
        Optional<ButtonType> result = dialog.showAndWait(); 
    }
  }

EditContactController.java

   package sample;

    import javafx.fxml.FXML;
    import javafx.scene.control.TextArea;
    import javafx.scene.control.TextField;
    import javafx.stage.Stage;
    import sample.datamodel.Contact;


    public class EditContactController{

    @FXML
    private TextField fName;
    @FXML
    private TextField lName;
    @FXML
    private TextField pNumber;
    @FXML
    private TextArea nNotes;
    @FXML
    private javafx.scene.control.Button cancelButton;

    @FXML
    private Contact item;

    public void setItem(Contact item) {
        this.item = item;
    }

    @FXML
    public void initialize(){
        try {
           fName.setText(item.getFirstName());
        }catch(NullPointerException e) {
            System.out.println("null point --> " + e.getMessage());
            e.printStackTrace();
        }
    }

    //@FXML
    public void cancelButtonAction(){
        // get a handle to the stage
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
    }

    }

editContact.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>

<GridPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.EditContactController">
    <HBox GridPane.columnSpan="2">
        <Label text="Edit contact">
            <font>
                <Font name="System Bold" size="17.0" />
            </font>
            <padding>
                <Insets bottom="10.0" left="10.0" />
            </padding></Label>
    </HBox>
    <Label text="First Name" GridPane.columnIndex="0" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1">
        <GridPane.margin>
            <Insets left="10.0" />
        </GridPane.margin>
        <padding>
            <Insets bottom="5.0" />
        </padding></Label>
    <Label text="Last Name" GridPane.columnIndex="0" GridPane.rowIndex="2">
        <GridPane.margin>
            <Insets bottom="5.0" left="10.0" />
        </GridPane.margin></Label>
    <Label text="Phone number" GridPane.columnIndex="0" GridPane.rowIndex="3">
        <GridPane.margin>
            <Insets bottom="5.0" left="10.0" />
        </GridPane.margin></Label>
    <Label text="Notes" GridPane.columnIndex="0" GridPane.rowIndex="4">
        <GridPane.margin>
            <Insets bottom="5.0" left="10.0" />
        </GridPane.margin></Label>

    <TextField fx:id="fName" GridPane.columnIndex="1" GridPane.rowIndex="1">
        <GridPane.margin>
            <Insets bottom="5.0" />
        </GridPane.margin></TextField>
    <TextField fx:id="lName" GridPane.columnIndex="1" GridPane.rowIndex="2">
        <GridPane.margin>
            <Insets bottom="5.0" />
        </GridPane.margin></TextField>
    <TextField fx:id="pNumber" GridPane.columnIndex="1" GridPane.rowIndex="3">
        <GridPane.margin>
            <Insets bottom="5.0" />
        </GridPane.margin></TextField>
    <TextArea fx:id="nNotes" GridPane.columnIndex="1" GridPane.rowIndex="4">
    <GridPane.margin>
        <Insets bottom="5.0" />
    </GridPane.margin></TextArea>
    <HBox alignment="TOP_RIGHT" spacing="5.0" GridPane.columnIndex="1" GridPane.rowIndex="5">
        <Button text="Edit">
            <opaqueInsets>
                <Insets />
            </opaqueInsets></Button>
        <Button fx:id="cancelButton" cancelButton="true" onAction="#cancelButtonAction" text="Cancel" />
        <opaqueInsets>
            <Insets />
        </opaqueInsets>
        <GridPane.margin>
            <Insets />
        </GridPane.margin>
        <padding>
            <Insets bottom="5.0" left="5.0" right="5.0" />
        </padding>
    </HBox>


    <columnConstraints>
        <ColumnConstraints maxWidth="288.0" minWidth="22.0" prefWidth="129.0" />
        <ColumnConstraints maxWidth="578.0" minWidth="312.0" prefWidth="471.0" />
    </columnConstraints>
    <rowConstraints>
        <RowConstraints />
        <RowConstraints />
        <RowConstraints />
        <RowConstraints />
        <RowConstraints />
        <RowConstraints />
    </rowConstraints>
    <padding>
        <Insets left="5.0" right="5.0" top="5.0" />
    </padding>
    <opaqueInsets>
        <Insets />
    </opaqueInsets>

    </GridPane>

堆栈:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    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.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.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.Node.fireEvent(Node.java:8413)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    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.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:394)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
    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$147(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
    ... 48 more
Caused by: java.lang.NullPointerException
    at sample.Controller.showEditContactDialog(Controller.java:105)
    ... 58 more

1 个答案:

答案 0 :(得分:0)

您的控制器类在FXML文件中指定,因此FXMLLoader在读取该文件之前无法实例化它。这意味着控制器仅在调用load()期间创建,并且在此之前调用fxmlLoader.getController()将返回null。

因此,您需要移动检索控制器的代码并对其进行操作,以便在调用load()后执行

public void showEditContactDialog() throws Exception {
    Dialog<ButtonType> dialog = new Dialog<>();
    dialog.initOwner(mainBorderPane.getScene().getWindow());
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setLocation(getClass().getResource("editContact.fxml"));

    try {

        Parent dialogContent = fxmlLoader.load();
        EditContactController editController = fxmlLoader.<EditContactController>getController();
        editController.setItem(item); 


        dialog.getDialogPane().setContent(dialogContent); 

    } catch (IOException e) {
        System.out.println("Couldn't load the dialog");
        e.printStackTrace();
        return;
    }
    Optional<ButtonType> result = dialog.showAndWait(); 
}

在调用initialize()期间,还会调用控制器中的FXMLLoader.load()方法。因此,由于这些更改,现在在initialize()上调用setItem(...)之前调用EditContactController。因此,您需要将依赖于initialize()方法中的项目的代码移动到setItem()方法:

public void setItem(Contact item) {
    this.item = item;
    fName.setText(item.getFirstName());
}


@FXML
public void initialize(){

}