【问题标题】:JavaFX - problem with TableView (NullPointerException)JavaFX - TableView 的问题(NullPointerException)
【发布时间】:2021-09-07 20:39:55
【问题描述】:

JavaFX 中的 TableView 控件存在很大问题。这是我第一次使用它,我不知道我做错了什么。

我的代码:

主类:

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);
    }
}

控制器类:

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();
        }
    }
}

人物类:

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);
    }
}

还有两个 FXML 代码,一个用于我们运行代码时显示的窗口:

sample.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>

还有一个用于 TableView 的新阶段:

mainWindow.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>

所以问题是 - 我无法设置 TableView 的项目,因为我得到一个异常,即它为空,即使它清楚地显示在新阶段(我相信)它确实存在。

错误代码:

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

【问题讨论】:

  • 创建并发布minimal reproducible example
  • 好的,你现在可以看看@James_D @kleopatra 吗?我已经尽可能简单了,但它仍然会产生同样的问题。
  • 顺便说一句,对问题的编辑非常好。这正是创建minimal reproducible example的方法。
  • @JimD 它如何帮助排除故障?您从堆栈跟踪中知道它是空的。如果您内联初始化它,您知道它不会为空。这根本没有提供任何信息。应用程序已经运行,所以如果你想在调试器中运行它,你可以在你引用表格之前设置一个断点,如果你需要,可以单步执行。
  • @JimD 但是如果它被注释为@FXML 并且它是空的,你已经知道注入没有工作。如果你初始化它,你就知道会发生什么——它不会再为空了。你不会从中学到任何东西。您的建议不合逻辑,会使人们对事情的运作方式感到困惑。

标签: java javafx null tableview


【解决方案1】:

问题是您尝试对两个 FXML 文件使用相同的控制器类(我认为,假设这意味着您两次都将拥有相同的控制器实例,但事实并非如此)。

在加载sample.fxml 时创建的Controller 实例上调用openNewWindow() 方法。该 FXML 文件没有名为 peopleTableView 的字段,因此 peopleTableView 在该实例中为空,peopleTableView.setItems(...) 导致空指针异常。

peopleTableView 字段在您加载 mainWindow.fxml 时创建的 Controller 实例中进行初始化,但没有在该实例上调用任何方法。

解决方案是为每个 FXML 文件使用不同的控制器类(您基本上应该始终这样做)。可以使用mainWindow.fxml的控制器中的initialize()方法来初始化表数据。

这是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();
        }
    }
}

这是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);
    }
}

现在只需更新两个 FXML 文件中的 fx:controller 属性即可。

如果您需要将数据从一个控制器传递到下一个控制器,请参阅Passing Parameters JavaFX FXML

例如,如果您想在第一个控制器的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();
        }
    }
}

public class MainController {

    @FXML
    private TableView<Person> peopleTableView ;

    public void initializeTableData(ObservableList<Person> people) {

        peopleTableView.setItems(people);
    }
}

但同样,有关控制器之间通信的各种方式的完整讨论,请参阅Passing Parameters JavaFX FXML

【讨论】:

  • 非常感谢,它工作得很好。我实际上觉得这很奇怪,因为在我的项目中,我有两个属于一个 Controller 类的 fxml 文件,它们工作得很好,但由于某种原因,第三个与 TableView 不能合作。无论如何,我可能应该添加另一个控制器来分隔前两个 fxmls 文件,只是为了养成好习惯。
猜你喜欢
  • 2017-04-04
  • 2014-10-21
  • 1970-01-01
  • 2015-07-20
  • 2023-04-08
  • 2012-07-01
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多