JavaFX,为什么 TableColumn 为空?

JavaFX, why is TableColumn null?

如您所见,在 Java 和 Javafx 方面,我是个大菜鸟。我花了很多时间四处阅读(各种论坛 posts 和 tuts)并试图弄清楚我自己在哪里遇到这个问题但是我已经到了 post 的地步来自了解他们业务的人的反馈。

回复时,能否请您也花点时间解释一下为什么有些东西不起作用以及一些一般性的建议?这是我目前所拥有的(我的 FXML 和我的两个 classes)任何指针都会很棒!

我的 FXML;

<Pane id="myScene" fx:id="myScene" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
      prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
        fx:controller="sample.TestController">
   <children>
      <TableView id="employeesTable" fx:id="employeesTable" layoutX="131.0" layoutY="64.0" prefHeight="200.0" prefWidth="360.0">
        <columns>
          <TableColumn id="colFirstName" fx:id="colFirstName" prefWidth="75.0" text="First Name" />
          <TableColumn id="colLastName" fx:id="colLastName" prefWidth="75.0" text="Last Name" />
            <TableColumn id="colEmail" fx:id="colEmail" prefWidth="75.0" text="email" />
        </columns>
      </TableView>
   </children>
</Pane>

现在员工class我有;

public class Employee {

private StringProperty firstName;
private StringProperty lastName;
private StringProperty email;


public Employee(String a, String b, String c) {
    this.firstName = new SimpleStringProperty(a);
    this.lastName = new SimpleStringProperty(b);
    this.email = new SimpleStringProperty(c);
}

public Employee() {
}


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

public StringProperty firstNameProperty() {
    return firstName;
}

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

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

public StringProperty lastNameProperty() {
    return lastName;
}

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

public String getEmail() {
    return email.get();
}

public StringProperty emailProperty() {
    return email;
}

public void setEmail(String email) {
    this.email.set(email);
}

}

最后,我的测试控制器 class 是

public class TestController {
public Label login;
public TextField loginUserName;
public PasswordField loginPassword;
public TextField testOutput;
@FXML TableView<Employee> employeesTable;
@FXML TableColumn<Employee, String> colFirstName;
@FXML TableColumn<Employee, String> colLastName;
@FXML TableColumn<Employee, String> colEmail;
@FXML Pane myScene;

//public javafx.scene.control.TableView employeesTable;
private ObservableList<Employee> myData;
private MainController MainController;

public void loadEmployeeForm(ActionEvent actionEvent) throws IOException, SQLException, ClassNotFoundException {
    myData = FXCollections.observableArrayList(DBCON.getEmployees());
    System.out.println(myData.size());
    Parent root = FXMLLoader.load(getClass().getResource("frmEmployees.fxml"));
    Scene myScene = new Scene( root );
    sample.MainController.setScene(myScene);
    colFirstName.setCellValueFactory(new PropertyValueFactory<Employee, String>("firstName"));
    colLastName.setCellValueFactory(new PropertyValueFactory<Employee, String>("lastName"));
    colEmail.setCellValueFactory(new PropertyValueFactory<Employee, String>("email"));
    employeesTable.setItems(null);
    employeesTable.setItems(myData);
    employeesTable.setVisible(true);
}

当我将 colFirstName 设置为 属性 值工厂时出现空指针异常,这让我觉得我没有在某处初始化某些东西,但我完全不知道如何添加它。

如果我添加以下行; TableColumn colFirstName = new TableColumn("firstName");

对于我的每个列和表名,它都是这样工作的(即它不会向我抛出大量错误消息)但后来我没有将任何数据加载到表视图中,因为我认为那是我创建一个新的 tableView 不使用从 FXML 生成的?

我觉得它会很简单,但正如我所说的,我是一个大菜鸟,任何点都非常有必要。

谢谢 马克

更新 1;

从 myMain.fxml 上的按钮调用加载员工表单的方法;

    <GridPane alignment="CENTER" hgap="10" prefHeight="300" prefWidth="300" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"
          fx:controller="sample.TestController" stylesheets="/sample/myFirst.css">
    <children>
       <Button onAction="#login" text="Login" GridPane.halignment="CENTER" GridPane.rowIndex="5" GridPane.valignment="CENTER" />
        <Button text="GoEmployees" onAction="#loadEmployeeForm" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
       <Label fx:id="login" GridPane.rowIndex="1" />
      <Label text="UserName" GridPane.columnIndex="0" GridPane.rowIndex="1" />
      <Label text="Password" GridPane.columnIndex="0" GridPane.rowIndex="2" />
      <TextField fx:id="loginUserName" GridPane.rowIndex="1" GridPane.columnIndex="1" />
      <PasswordField fx:id="loginPassword" GridPane.rowIndex="2" GridPane.columnIndex="1" blendMode="OVERLAY" />
        <TextField fx:id="testOutput" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="3" />
   </children>
   <columnConstraints>
      <ColumnConstraints prefWidth="125.0" />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints prefHeight="50.0" />
   </rowConstraints>
   <padding>
      <Insets bottom="10.0" left="9.0" right="10.0" top="10.0" />
   </padding>

</GridPane>

让我的 testController 控制两个不同的 FXML problem/a 不行吗?

您从不使用 Employee(String, String, String) 构造函数。此构造函数初始化 firstNamelastNameemail。否则,您的引用将毫无意义。

FXMLLoader 尝试加载 fxml 文件时,它将创建控制器 class 在 fxml 文件中用 fx:controller 定义的新实例。然后它 创建 并将 @FXML 注释字段映射到 fxml 文件中的 fx:id 组件。最后,它调用控制器的 initialize() 方法。您可以在 fxmlloader.load().

之后使用 fxmlloader.getController() 获取实例化的控制器

根据这个基本工作流程,你的代码中的陷阱是:
myMain.fxml 的控制器是 TestController,但是 myMain.fxml 不包含具有 fx:id colFirstName 等的 TableColumns。因此,当 myMain.fxml 已加载时,这些字段为空。因此,在尝试使用这些字段时,loadEmployeeForm() 中将出现 NPE。

将 TableView 和 TableColumns 移动到 frmEmployees.fxml 的控制器,并在该控制器的 initialize() 方法中配置它们(setCellValueFactory、初始数据等)。