简体   繁体   English

JavaFX - TableView 问题(NullPointerException)

[英]JavaFX - problem with TableView (NullPointerException)

I am having a huge problem with TableView control in JavaFX.我在 JavaFX 中使用 TableView 控件时遇到了一个大问题。 That's the first time I'm ever using it and I don't know what am I doing wrong.那是我第一次使用它,我不知道我做错了什么。

My code:我的代码:

Main class:主要类:

package sample;

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

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

Controller class:控制器类:

package sample;

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.TableView;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller {

    @FXML
    private TableView<Person> peopleTableView;

    @FXML
    public void openNewWindow(){
        try {
            Parent root = FXMLLoader.load(getClass().getResource("mainWindow.fxml"));
            Stage mainWindow = new Stage();
            mainWindow.setTitle("App");
            mainWindow.setScene(new Scene(root, 1200, 600));
            mainWindow.initModality(Modality.APPLICATION_MODAL);
            mainWindow.show();

            ObservableList<Person> people = FXCollections.observableArrayList();

            people.add(new Person("Walter", "White"));
            people.add(new Person("Gus", "Fring"));

            peopleTableView.setItems(people);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Person class:人物类:

package sample;

import javafx.beans.property.SimpleStringProperty;

public class Person {

    private SimpleStringProperty firstName = new SimpleStringProperty("");
    private SimpleStringProperty lastName = new SimpleStringProperty("");

    public Person(String firstName, String lastName) {
        this.firstName.set(firstName);
        this.lastName.set(lastName);
    }

    public String getFirstName() {
        return firstName.get();
    }

    public SimpleStringProperty firstNameProperty() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public String getLastName() {
        return lastName.get();
    }

    public SimpleStringProperty lastNameProperty() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }
}

And two FXMLs codes, one for the window that shows up when we run the code:还有两个 FXML 代码,一个用于运行代码时显示的窗口:

sample.fxml:示例.fxml:

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane fx:controller="sample.Controller"
            xmlns:fx="http://javafx.com/fxml">
    <center>
        <Button fx:id="openWindowButton" text="Open new window" onAction="#openNewWindow"/>
    </center>
</BorderPane>

And one for the new stage with TableView:还有一个用于 TableView 的新阶段:

mainWindow.fxml:主窗口.fxml:

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.scene.control.cell.PropertyValueFactory?>
<BorderPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
    <center>
        <TableView fx:id="peopleTableView">
            <columns>
                <TableColumn text="First Name">
                    <cellValueFactory>
                        <PropertyValueFactory property="firstName"/>
                    </cellValueFactory>
                </TableColumn>
                <TableColumn text="Last Name">
                    <cellValueFactory>
                        <PropertyValueFactory property="lastName"/>
                    </cellValueFactory>
                </TableColumn>
            </columns>
        </TableView>
    </center>
</BorderPane>

So the issue is - I can't set items of TableView, because I get an exception that it is null even though it clearly shows up in the new stage which (I believe) it actually exists.所以问题是 - 我无法设置 TableView 的项目,因为我得到一个例外,即它为空,即使它清楚地显示在(我相信)它实际存在的新阶段。

Error code:错误代码:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1787)
    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.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:8879)
    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.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:3851)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1200(Scene.java:3579)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2588)
    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:390)
    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.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.reflect.InvocationTargetException
    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:566)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    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:566)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1784)
    ... 47 more
Caused by: java.lang.NullPointerException
    at TableView.issue/sample.Controller.openNewWindow(Controller.java:35)
    ... 59 more

The problem is you're trying to use the same controller class for both FXML files (I think, assuming that this means you'll have the same controller instance both times, which is not the case).问题是您试图对两个 FXML 文件使用相同的控制器类(我认为,假设这意味着您两次都拥有相同的控制器实例,但事实并非如此)。

The openNewWindow() method is called on the Controller instance that is created when you load sample.fxml .在加载sample.fxml时创建的Controller实例上调用openNewWindow()方法。 That FXML file has no field called peopleTableView , so peopleTableView is null in that instance, and peopleTableView.setItems(...) results in a null pointer exception.该 FXML 文件没有名为peopleTableView字段,因此在该实例中peopleTableView为空,而peopleTableView.setItems(...)导致空指针异常。

The peopleTableView field is initialized in the Controller instance that is created when you load mainWindow.fxml , but no methods are called on that instance. peopleTableView字段在加载mainWindow.fxml时创建的Controller实例中初始化,但没有在该实例上调用任何方法。

The solution is to use a different controller class for each FXML file (you should basically always do this).解决方案是为每个 FXML 文件使用不同的控制器类(您基本上应该始终这样做)。 You can use the initialize() method in the controller for mainWindow.fxml to initialize the table data.您可以使用mainWindow.fxml控制器中的initialize()方法来初始化表数据。

Here's the controller for sample.fxml :这是sample.fxml的控制器:

public class LoginController {

    @FXML
    public void openNewWindow(){
        try {
            Parent root = FXMLLoader.load(getClass().getResource("mainWindow.fxml"));
            Stage mainWindow = new Stage();
            mainWindow.setTitle("App");
            mainWindow.setScene(new Scene(root, 1200, 600));
            mainWindow.initModality(Modality.APPLICATION_MODAL);
            mainWindow.show();

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

And here's the controller for mainWindow.fxml :这是mainWindow.fxml的控制器:

public class MainController {

    @FXML
    private TableView<Person> peopleTableView ;

    @FXML
    private void initialize() {
        ObservableList<Person> people = FXCollections.observableArrayList();

        people.add(new Person("Walter", "White"));
        people.add(new Person("Gus", "Fring"));


        peopleTableView.setItems(people);
    }
}

Now just update the fx:controller attributes in both FXML files.现在只需更新两个 FXML 文件中的fx:controller属性。

If you need to pass data from one controller to the next, see Passing Parameters JavaFX FXML如果您需要将数据从一个控制器传递到下一个控制器,请参阅传递参数 JavaFX FXML

For example, if you wanted to load the table data in the first controller's openNewWindow() method (which seems unnatural, but will serve as an example), you could do:例如,如果您想在第一个控制器的openNewWindow()方法中加载表数据(这看起来不自然,但可以作为示例),您可以这样做:

public class LoginController {

    @FXML
    public void openNewWindow(){
        try {

            // Note using FXMLLoader instance, not static load(URL) method:
            FXMLLoader loader = new FXMLLoader(getClass().getResource("mainWindow.fxml"));
            Parent root = loader.load();

            Stage mainWindow = new Stage();
            mainWindow.setTitle("App");
            mainWindow.setScene(new Scene(root, 1200, 600));
            mainWindow.initModality(Modality.APPLICATION_MODAL);
            mainWindow.show();

            ObservableList<Person> people = FXCollections.observableArrayList();

            people.add(new Person("Walter", "White"));
            people.add(new Person("Gus", "Fring"));

            MainController mainController = loader.getController();
            mainController.initializeTableData(people);

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

and

public class MainController {

    @FXML
    private TableView<Person> peopleTableView ;

    public void initializeTableData(ObservableList<Person> people) {

        peopleTableView.setItems(people);
    }
}

But again, for a full discussion of the various ways to communicate between controllers, see Passing Parameters JavaFX FXML但同样,有关控制器之间通信的各种方式的完整讨论,请参阅传递参数 JavaFX FXML

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM