JavaFx 表视图运行时异常

JavaFx tableview RuntimeException

我只是想用 SceneBuilder 和 JavaFx 构建一个简单的 Gui,但是我不明白为什么我不能填充我的 TableView,即使在插入简单的 Testobjects 之后它仍然是空的。这是主要 Class 和目标 class。

package application;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.util.ResourceBundle;

import Objects.Goal;
import UtilityClasses.GoalManager;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;



public class Main extends Application implements Initializable  {
    private Stage primaryStage;
    private AnchorPane mainLayout;
    public static ObservableList<Goal> goalsData = FXCollections.observableArrayList();

    @FXML
    static TableView<Goal> goalTable = new TableView<Goal>();
    @FXML
    static TableColumn<Goal, String> goalsColumn = new TableColumn<>();
    @FXML
    static TableColumn<Goal, String> statusColumn = new TableColumn<>();

    @Override
    public void start(Stage primaryStage) {


            this.primaryStage = primaryStage;
            this.primaryStage.setTitle("MainWindow");

            try {
                showMainView();
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }











    }

    public static void main(String[] args) {

        try {
            setDefaultSettings();
            launch(args);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }

    private void showMainView() throws IOException {
        SettingControlls mainController = new SettingControlls();
        FXMLLoader loader = new FXMLLoader();
        loader.setController(mainController);
        loader.setLocation(Main.class.getResource("mainFXML.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    private static void setDefaultSettings() throws IOException {

        File f = new File("Goals.txt");
        if(!f.exists()) {
            OutputStream os = new FileOutputStream("Goals.txt");
            Writer w = new OutputStreamWriter(os);
            w.close();
        }


    }
    private static ObservableList<Goal> getObservableList() throws FileNotFoundException, IOException {

        ObservableList<Goal> ol = FXCollections.observableArrayList(new Goal("testGoal"));
        return ol;

    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        goalsData.add(new Goal("test"));
        System.out.println(goalsData.get(0).getGoal());
        goalsColumn.setCellValueFactory(new PropertyValueFactory<Goal, String>("goal"));
        statusColumn.setCellValueFactory(new PropertyValueFactory<Goal, String>("status"));


        goalTable.setItems(goalsData);

    }
}

这是目标 class:

package Objects;

import javafx.beans.property.SimpleStringProperty;

public class Goal {


    private SimpleStringProperty goal;
    private SimpleStringProperty status;

    public Goal(String goal) {


        this.goal = new SimpleStringProperty(goal);
        this.status = new SimpleStringProperty("ongoing");
    }
    public Goal(String goal, String status) {


        this.goal = new SimpleStringProperty(goal);
        this.status = new SimpleStringProperty(status);
    }

    public String getGoal() {
        return this.goal.get();
    }
    public String getStatus() {
        return this.status.get();
    }
    public void setGoal(String newGoal) {

        this.goal = new SimpleStringProperty(newGoal);
    }
    public void setStatus(String newStatus) {

        this.status = new SimpleStringProperty(newStatus);
    }

}

因为 TableView 和列是在我的 fxml 文件中声明的,所以用 new 生成它们对我来说似乎很奇怪,但是如果我不这样做,我会得到 Nullpointerexception。

编辑:添加了 fxml 文件:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ContextMenu?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>

<AnchorPane prefHeight="406.0" prefWidth="721.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <MenuBar layoutX="-7.0" layoutY="14.0" prefHeight="25.0" prefWidth="733.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <menus>
          <Menu mnemonicParsing="false" onAction="#GoalsClicked" style="-fx-font-size: 23;" text="Goals" />
          <Menu disable="true" mnemonicParsing="false" style="-fx-font-size: 23;" text="Matchups" />
        </menus>
      </MenuBar>
      <Text layoutX="14.0" layoutY="87.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Your current Goals:">
         <font>
            <Font size="24.0" />
         </font>
      </Text>
      <TableView fx:id="goalTable" layoutY="103.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0">
        <columns>
          <TableColumn fx:id="goalsColumn" maxWidth="1.7976931348623157E308" minWidth="0.0" prefWidth="625.0" text="Goals" />
          <TableColumn fx:id="statusColumn" maxWidth="1.7976931348623157E308" minWidth="0.0" prefWidth="72.0" text="Status" />
        </columns>
         <contextMenu>
            <ContextMenu>
              <items>
                <MenuItem mnemonicParsing="false" text="Delete" />
                  <MenuItem mnemonicParsing="false" text="Set status" />
              </items>
            </ContextMenu>
         </contextMenu>
      </TableView>
      <Button layoutX="619.0" layoutY="315.0" mnemonicParsing="false" onAction="#addGoal" text="+" />
      <Button layoutX="655.0" layoutY="315.0" mnemonicParsing="false" onAction="#removeGoal" text="-" />
   </children>
</AnchorPane>

你那里有很多问题:

  1. 不建议将您的Mainclass用作Controllerclass。
  2. 您在 .fxml 中使用的 Node 永远不会是静态的,因为它们属于实例而不属于 class,因此请删除它们。
  3. 不要实例化 .fxml 文件中定义的 Node。与new无关。 FXMLLoader 为您代劳。

所以重写以下部分:

    @FXML
    static TableView<Goal> goalTable = new TableView<Goal>();
    @FXML
    static TableColumn<Goal, String> goalsColumn = new TableColumn<>();
    @FXML
    static TableColumn<Goal, String> statusColumn = new TableColumn<>();

我还建议将 Main class 拆分为 MainController class。 在 Main 中,您应该只加载文件,并在 Controller 中执行 UI 相关的操作。 您可以通过以下方式拆分:

主要:

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

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("View.fxml"));
        AnchorPane pane = loader.load();
        primaryStage.setScene(new Scene(pane, 400, 400));
        primaryStage.show();
    }
}

控制器:

import javafx.fxml.Initializable;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    }

}

.fxml

<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="Whosebug.dummy.Controller">

</AnchorPane>

然后您可以根据我在 2. 和 3.

中提到的两条规则完成这些 classes