从文本字段中提取空数据。表已填充,但无法检索对象。 Java/JavaFX

Posted

技术标签:

【中文标题】从文本字段中提取空数据。表已填充,但无法检索对象。 Java/JavaFX【英文标题】:Pulling null data from text fields. Table is populated, but can't retrieve objects. Java / JavaFX 【发布时间】:2018-02-06 04:19:21 【问题描述】:

我正在使用的主屏幕上有两个表格。

零件表和产品表。产品由零件组成。零件表的表功能(搜索、选择等)都可以正常工作。当一个新产品被创建并添加到表中时,它似乎就在那里。但是,当我尝试检索数据以进行修改时,通过使用数据初始化 Product 字段,我得到一个 NPE。使用与零件表相同的搜索功能时,搜索功能不会找到零件。

列出的是有问题的文件...

MainScreenController.java

/**
 * Sample Skeleton for 'MainScreen.fxml' Controller Class
 */

package jbernsd_IMS.View;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import jbernsd_IMS.MainApp;
import jbernsd_IMS.Model.Inventory;
import jbernsd_IMS.Model.Part;
import jbernsd_IMS.Model.Product;


public class MainScreenController 

 // Table and column declarations for Part table.
// fx:id partTableMain
    @FXML
    private TableView<Part> partTableMain;

// fx:ids are respective...ie partIdColumnMain, partInvColumnMain, etc.
    @FXML
    private TableColumn<Part, Integer> partIdColumnMain, partInvColumnMain;

// fx:id partNameColumnMain;
    @FXML
    private TableColumn<Part, String> partNameColumnMain;

// fx:id partCostColumnMain
    @FXML
    private TableColumn<Part, Double> partCostColumnMain;

// Table and column declarations for Product table.
// fx:id productTableMain
    @FXML
    private TableView<Product> productTableMain;

// fx:ids are respective...ie productIdColumnMain, productInvColumnMain, etc.
    @FXML
    private TableColumn<Product, Integer> productIdColumnMain, productInvColumnMain;

// fx:id productNameColumnMain
    @FXML
    private TableColumn<Product, String> productNameColumnMain;

// fx:id productCostColumnMain
    @FXML
    private TableColumn<Product, Double> productCostColumnMain;

// fx:ids are respective...ie addPartButtonMain, modPartButtonMain, etc.
    @FXML
    private Button addPartButtonMain, modPartButtonMain, delPartButtonMain, searchPartButtonMain,
       addProductButtonMain, modProductButtonMain, delProductButtonMain, searchProductButtonMain,
            exitButton;

// fx:ids are respective...ie searchPartFieldMain, searchProductFieldMain, etc.
    @FXML
    private TextField searchPartFieldMain, searchProductFieldMain;

    private boolean okClicked = false;

// Reference to the main application...
    private MainApp mainApp;    

    /**
     * The MainScreenController (MSC) no-argument Constructor
     * The constructor is called before the initialize() method.
     */
    public MainScreenController() 
    

    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    @FXML
    private void initialize() 
        partIdColumnMain.setCellValueFactory(cellData -> cellData.getValue().partIdProperty().asObject());
        partNameColumnMain.setCellValueFactory(cellData -> cellData.getValue().partNameProperty());
        partInvColumnMain.setCellValueFactory(cellData -> cellData.getValue().partInvProperty().asObject());
        partCostColumnMain.setCellValueFactory(cellData -> cellData.getValue().partCostProperty().asObject());



        productIdColumnMain.setCellValueFactory(cellData -> cellData.getValue().productIdProperty().asObject());
        productNameColumnMain.setCellValueFactory(cellData -> cellData.getValue().productNameProperty());
        productInvColumnMain.setCellValueFactory(cellData -> cellData.getValue().productInvProperty().asObject());
        productCostColumnMain.setCellValueFactory(cellData -> cellData.getValue().productCostProperty().asObject());

    
//    setText(String.format("%0.2f", value.doubleValue()));
    /**
     * Is called by the main application to give reference to itself.
     * 
     * @param mainApp
     */
    public void setMainApp(MainApp mainApp) 
        this.mainApp = mainApp;
        // Add observable list data to the table
        partTableMain.setItems(Inventory.getAllParts());
        productTableMain.setItems(Inventory.getProducts());
    

// onAction="#handleNewPart"
    @FXML
    private void handleNewPart() 
        okClicked = mainApp.showAddPartScreen();
    
// onAction="#handleNewProduct"
    @FXML
    private void handleNewProduct() 
        okClicked = mainApp.showAddProductScreen();
    

// onAction="#handleModPart"    
    @FXML
    private void handleModPart(ActionEvent e)  

        Inventory.selectedPart = partTableMain.getSelectionModel().getSelectedItem();
        Part selectedPart = Inventory.selectedPart;

        if(selectedPart != null) 

            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle("Selection Confirmation");
            alert.setHeaderText("Please confirm the part you selected...");
            alert.setContentText("You have selected: \n\n"
                    + "Part ID: \t\t" + selectedPart.partIdProperty().getValue() + "\n"
                    + "Part Name: \t" + selectedPart.partNameProperty().getValueSafe() + "\n\n");            
            alert.showAndWait()
                    .filter(response -> response == ButtonType.OK)
                    .ifPresent(response -> mainApp.showModPartScreen());

            okClicked = true;

         else                                                           //                                       //
                // Nothing selected...                                                                                 
                Alert alert = new Alert(Alert.AlertType.WARNING);                                                      
                alert.setTitle("No selection");                                                                        
                alert.setHeaderText("No part selected");                                                               
                alert.setContentText("Please select a part in the table.");                                            
                alert.showAndWait()
                        .filter(response -> response == ButtonType.OK)
                        .ifPresent(response -> alert.close());

                okClicked = false;
        
    

    // onAction="#handleModProduct"    
    @FXML
    private void handleModProduct(ActionEvent e) 
//        productTableMain.setOnMouseClicked((MouseEvent event) -> 
//            if(event.getButton().equals(MouseButton.PRIMARY)) 
//        );

        Inventory.selectedProduct = productTableMain.getSelectionModel().getSelectedItem();
        Product selectedProduct = Inventory.selectedProduct;

        if(selectedProduct != null) 
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle("Selection Confirmation");
            alert.setHeaderText("Please confirm the product you selected...");
            alert.setContentText("You have selected: \n\n"
                    + "Product ID: \t\t" + selectedProduct.productIdProperty().getValue() + "\n"
                    + "Product Name: \t" + selectedProduct.productNameProperty().getValueSafe() + "\n\n");
            alert.showAndWait()
                    .filter(response -> response == ButtonType.OK)
                    .ifPresent(response -> mainApp.showModProductScreen());
            okClicked = true;

         else                                                           //                                       //
                // Nothing selected...                                                                                 
                Alert alert = new Alert(Alert.AlertType.WARNING);                                                      
                alert.setTitle("No selection");                                                                        
                alert.setHeaderText("No products selected");                                                               
                alert.setContentText("Please select a product in the table.");                                            
                alert.showAndWait()
                        .filter(response -> response == ButtonType.OK)
                        .ifPresent(response -> alert.close());
                okClicked = false;
                                                                                                                  
    

        // fx:id foundMe
    @FXML
    private void foundMe() 
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("Easter Egg!! (Illegal after 9/11)");
        alert.setHeaderText("Congratulations!!!");
        alert.setContentText("Congratulations!! You found my Easter Egg!!!  :) ");
        alert.showAndWait();
    


    @FXML
    private void handleClose(ActionEvent e) 
        Platform.exit();        
    

    /**
     * Called when the user clicks on the delete button.
     */

    @FXML
    private void handleDelete(ActionEvent e)                                                                      

        Part selectedPart = partTableMain.getSelectionModel().getSelectedItem();                                   

            if(selectedPart != null)                                                                                  
                // Confirm deletion                                                                                    
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION);                                                 
                alert.setTitle("Confirm Deletion");                                                                    
                alert.setHeaderText("Deleting...");                                                                    
                alert.setContentText("Are you sure you want to delete the part? \n\n"
                        + "Part ID: \t\t" + selectedPart.partIdProperty().getValue() + "\n"
                        + "Part Name: \t" + selectedPart.partNameProperty().getValueSafe()); 
                alert.showAndWait()                                                                                    
                        .filter(response -> response  ==  ButtonType.OK)                                                 
                        .ifPresent(response -> Inventory.getAllParts().remove(selectedPart));                             

                // Update partTableMain                                                                                
                partTableMain.setItems(Inventory.getAllParts());

             else 
                // Nothing selected...                                                                                 
                Alert alert = new Alert(Alert.AlertType.WARNING);                                                      
                alert.setTitle("No selection");                                                                        
                alert.setHeaderText("No part selected");                                                               
                alert.setContentText("Please select a part in the table.");                                            
                alert.showAndWait();
                                                                                                                  
    


     @FXML
    private void handleDeleteProd(ActionEvent e)                                                                      

        Product selectedProduct = productTableMain.getSelectionModel().getSelectedItem();                                   

            if(selectedProduct != null)                                                                                  
                // Confirm deletion                                                                                    
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION);                                                 
                alert.setTitle("Confirm Deletion");                                                                    
                alert.setHeaderText("Deleting...");                                                                    
                alert.setContentText("Are you sure you want to delete the product? \n\n"
                        + "Part ID: \t\t" + selectedProduct.productIdProperty().getValue() + "\n"
                        + "Part Name: \t" + selectedProduct.productNameProperty().getValueSafe()); //
                alert.showAndWait()                                                                                    
                        .filter(response -> response  ==  ButtonType.OK)                                                 
                        .ifPresent(response -> Inventory.getProducts().remove(selectedProduct));                             

                // Update partTableMain                                                                                
                productTableMain.setItems(Inventory.getProducts());

             else                                                           //                                       //
                // Nothing selected...                                                                                 
                Alert alert = new Alert(Alert.AlertType.WARNING);                                                      
                alert.setTitle("No selection");                                                                        
                alert.setHeaderText("No product selected");                                                               
                alert.setContentText("Please select a product in the table.");                                            
                alert.showAndWait();
                                                                                                                  
    

    @FXML
    private void searchPartTable() 
        String searchItem = searchPartFieldMain.getText();
        if(isSearchInputValid(searchItem))         
            FilteredList<Part> searchPartResults = searchParts(searchItem);
            SortedList<Part> sortedParts = new SortedList<>(searchPartResults);
            sortedParts.comparatorProperty().bind(partTableMain.comparatorProperty());
            partTableMain.setItems(sortedParts);
            searchPartFieldMain.clear();
        
    
    private FilteredList<Part> searchParts (String s) 
        return Inventory.getAllParts().filtered(p -> p.getPartName().toLowerCase().contains(s.toLowerCase()));
    


    @FXML
    void searchProductTable()         
        String searchItem = searchProductFieldMain.getText();

        if(isSearchInputValid(searchItem)) 
            FilteredList<Product> searchProductResults = searchProducts(searchItem);
            SortedList<Product> sortedProducts = new SortedList<>(searchProductResults);
            sortedProducts.comparatorProperty().bind(productTableMain.comparatorProperty());
            productTableMain.setItems(sortedProducts);
        
    
    public FilteredList<Product> searchProducts (String s) 
        return Inventory.getProducts().filtered(p -> p.getProductName().contains(s.substring(0, 1).toUpperCase()
                                                                               + s.substring(1).toLowerCase()));
     


    public boolean isSearchInputValid(String searchItem) 

        ObservableList<Part> list = FXCollections.observableArrayList(Inventory.getAllParts());

        String errorMessage = "";
        String partName;

        if(Inventory.getAllParts().isEmpty()) 
            errorMessage += "Inv: \t\t There are no parts in inventory to search. \n\n";
        

        if(!searchItem.equalsIgnoreCase("")) 
            int count = 0;
            for(Part p:Inventory.getAllParts()) 
                String name = p.partNameProperty().getValueSafe();

                if(!searchItem.equalsIgnoreCase(name)  || searchItem.equals(null)) 
                    count++;

                    if(count == Inventory.getAllParts().size()) 
                    errorMessage += "Inv: \t\t The search item, " + "\"" + searchItem + "\"" + " does not match \n" 
                            + "\t\t any known items in the inventory. \n\n"
                            + "\t\t The item cannot be found, or it does not exist. \n";
                    
                 
            
        

        if(errorMessage.length() == 0)     
            return true;

         else 
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("Error");
            alert.setHeaderText("Data Error Exists");
            alert.setContentText(errorMessage);
            alert.showAndWait();

            return false;
        
    

MainScreen.fxml

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jbernsd_IMS.View.MainScreenController">
   <children>
      <Rectangle fx:id="borderPartsMAIN" arcHeight="10.0" arcWidth="10.0" fill="TRANSPARENT"  layoutX="25.0" layoutY="56.0" stroke="#979797" strokeLineCap="BUTT" strokeLineJoin="ROUND" strokeType="OUTSIDE" strokeWidth="2.0"  />
      <Label fx:id="labelInvMgmtSysMAIN" layoutX="18.0" layoutY="15.0" text=" Inventory Management System">
         <font>
            <Font name="Calibri Italic" size="24.0" />
         </font>
      </Label>

      <!-- Parts section begins here -->
      <TableView fx:id="partTableMain" layoutX="35.0" layoutY="95.0" prefHeight="188.0" prefWidth="344.0">
        <columns>            
            <TableColumn fx:id="partIdColumnMain" prefWidth="54.0" text="Part ID">
                <cellValueFactory>
                    <PropertyValueFactory property="partID" />
                </cellValueFactory>
            </TableColumn>

            <TableColumn fx:id="partNameColumnMain" prefWidth="71.0" text="Part Name">
                <cellValueFactory>
                    <PropertyValueFactory property="partName" />
                </cellValueFactory>
            </TableColumn>

            <TableColumn fx:id="partInvColumnMain" minWidth="0.0" prefWidth="97.0" text="Inventory Level">
                <cellValueFactory>
                    <PropertyValueFactory property="partInv" />
                </cellValueFactory>
            </TableColumn>

            <TableColumn fx:id="partCostColumnMain" prefWidth="121.0" text="Price/Cost per Unit">
                <cellValueFactory>
                    <PropertyValueFactory property="partCost" />
                </cellValueFactory>
            </TableColumn>
        </columns>

      </TableView>
      <!-- Parts sections ends here -->

      <Label fx:id="labelPartsPrtsMAIN" layoutX="36.0" layoutY="58.0" text="Parts">
         <font>
            <Font name="Calibri Italic" size="24.0" />
         </font>
      </Label>
      <Button fx:id="searchPartButtonMain" layoutX="179.0" layoutY="63.0" mnemonicParsing="false" onAction="#searchPartTable" text="Search">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font></Button>
      <TextField fx:id="searchPartFieldMain" layoutX="241.0" layoutY="63.0" prefHeight="25.0" prefWidth="136.0" />
      <HBox layoutX="169.0" layoutY="294.0" spacing="15.0">
         <children>
            <Button fx:id="addPartButtonMain" mnemonicParsing="false" onAction="#handleNewPart" prefHeight="30.0" prefWidth="60.0" text="Add">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
            <Button fx:id="modPartButtonMain" mnemonicParsing="false" onAction="#handleModPart" prefHeight="30.0" prefWidth="60.0" text="Modify">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
            <Button fx:id="delPartButtonMain" mnemonicParsing="false" onAction="#handleDelete" prefHeight="30.0" prefWidth="60.0" text="Delete">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
         </children>
      </HBox>
      <!-- Parts section ends here -->

      <!-- Products section begins here -->
      <Rectangle fx:id="borderProdsMAIN" arcHeight="10.0" arcWidth="10.0" fill="TRANSPARENT"  layoutX="410.0" layoutY="56.0" stroke="#979797" strokeLineCap="BUTT" strokeLineJoin="ROUND" strokeType="OUTSIDE" strokeWidth="2.0"  />
      <TableView fx:id="productTableMain" layoutX="420.0" layoutY="95.0" prefHeight="188.0" prefWidth="344.0">
         <columns>
            <TableColumn fx:id="productIdColumnMain" prefWidth="54.0" text="Prod ID" />
            <TableColumn fx:id="productNameColumnMain" prefWidth="71.0" text="Prod Name" />
            <TableColumn fx:id="productInvColumnMain" minWidth="0.0" prefWidth="97.0" text="Inventory Level" />
            <TableColumn fx:id="productCostColumnMain" prefWidth="121.0" text="Price/Cost per Unit" />
         </columns>
      </TableView>
      <Label fx:id="labelProdsMAIN" layoutX="421.0" layoutY="58.0" text="Products">
         <font>
            <Font name="Calibri Italic" size="24.0" />
         </font>
      </Label>
      <Button fx:id="searchProductButtonMain" layoutX="564.0" layoutY="63.0" mnemonicParsing="false" onAction="#searchProductTable" text="Search">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font></Button>
      <TextField fx:id="searchProductFieldMain" layoutX="626.0" layoutY="63.0" prefHeight="25.0" prefWidth="136.0" />
      <HBox layoutX="554.0" layoutY="294.0" spacing="15.0">
         <children>
            <Button fx:id="addProductButtonMain" mnemonicParsing="false" onAction="#handleNewProduct" prefHeight="30.0" prefWidth="60.0" text="Add">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
            <Button fx:id="modProductButtonMain" mnemonicParsing="false" onAction="#handleModProduct" prefHeight="30.0" prefWidth="60.0" text="Modify">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
            <Button fx:id="delProductButtonMain" mnemonicParsing="false" onAction="#handleDeleteProd" prefHeight="30.0" prefWidth="60.0" text="Delete">
               <font>
                  <Font name="Calibri Italic" size="12.0" />
               </font></Button>
         </children>
      </HBox>
      <Button fx:id="foundMe" layoutX="309.0" layoutY="109.0" mnemonicParsing="false" onAction="#foundMe" prefHeight="2.0" prefWidth="2.0" textFill="TRANSPARENT" AnchorPane.bottomAnchor="288.0" AnchorPane.leftAnchor="309.0" AnchorPane.rightAnchor="489.0" AnchorPane.topAnchor="109.0">
         <font>
            <Font size="2.0" />
         </font>
      </Button>
      <Button fx:id="exitButton" layoutX="370.0" layoutY="356.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#handleClose" prefHeight="30.0" prefWidth="60.0" text="Exit">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font></Button>
      <!-- Products section ends here -->
   </children>
</AnchorPane>

【问题讨论】:

你在代码的哪里得到 NPE? 这是在不同的代码部分,我无法发布。这是我第一次在 SO/SE 上发帖,上面说我的字符数超过了。我还有另外两个文件要发布。我的解决方法是在我的 .fxml 文件中,我尝试填充的字段没有 fx:id 条目。菜鸟犯的菜鸟错误。因此,一旦我更正了 fx:id 条目以匹配我的字段名称,我就没事了。我非常想发布我的其他代码,以便人们可以从我的错误中得到一些使用,但由于字符数通知而不确定如何使用! 【参考方案1】:

我自己解决了问题。问题最终出在我的 .fxml 文件“ModifyProduct”中。没有与我试图填充的命名文本字段对应的 fx:id 等效项。因此,即使我已经实例化了这些字段,并且我的大部分逻辑都可以正常工作,但由于缺少可识别的名称,.fxml 根本无法将数据与字段相关联。一旦我解析了 .fxml 文件中的 fx:id 名称,数据就会正确流动......

修改ProductController.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package jbernsd_IMS.View;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import jbernsd_IMS.MainApp;
import jbernsd_IMS.Model.*;

/**
 *
 * @author JJ_2
 */
public class ModifyProductController 

    private IntegerProperty partIdMP;
    private IntegerProperty partNumberMP;
    private StringProperty partNameMP;
    private IntegerProperty partInvMP;
    private IntegerProperty partCostMP;


    public ModifyProductController()         
    
    private MainApp mainApp;

    private Label productIdLbl, productNameLbl, productInvLbl, productCostLbl, maxLbl, minLbl;

    @FXML
    private TextField productIdField, productNameField, productInvField, productCostField, minField, maxField, searchFieldModProds;

    private final ObservableList<Part> importedParts = FXCollections.observableArrayList(Inventory.getAllParts());

    private final ObservableList<Part> productParts = FXCollections.observableArrayList();


    // Parts to add
    // fx:id partTableAdd
    @FXML
    private TableView<Part> partTableAdd;   // Stores the found parts to add to the product.

    @FXML
    private TableColumn<Part, Integer> partIdColumnAdd, partInvColumnAdd;    // Holds the part ID and part Inv.

    @FXML
    private TableColumn<Part, String> partNameColumnAdd;   // Holds the part Name.

    @FXML
    private TableColumn<Part, Double> partCostColumnAdd;   // Holds the manufacturing cost of specified part.


    // Parts to remove
    // fx:id partTableDel
    @FXML
    private TableView<Part> partTableDel;   // Stores the found parts to delete from the product.

    @FXML
    private TableColumn<Part, Integer> partIdColumnDel, partInvColumnDel;    // Holds the part ID and part Inv.

    @FXML
    private TableColumn<Part, String> partNameColumnDel;   // Holds the part Name.

    @FXML
    private TableColumn<Part, Double> partCostColumnDel;   // Holds the manufacturing cost of specified part.

    @FXML
    private Stage dialogueStage;

    @FXML
    private boolean saveClicked = false;

    @FXML
    private boolean addClicked = false;

    public ObservableList<Part> getProdParts() 
        return productParts;
    

    private Product draftProduct;



    public Inventory inv;

    public MainScreenController msc;
    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    @FXML
    private void initialize() 

    // Set text fields.
        setTextFields();       

    // part table (top)        
        partIdColumnAdd.setCellValueFactory(cellData -> cellData.getValue().partIdProperty().asObject());
        partNameColumnAdd.setCellValueFactory(cellData -> cellData.getValue().partNameProperty());
        partInvColumnAdd.setCellValueFactory(cellData -> cellData.getValue().partInvProperty().asObject());
        partCostColumnAdd.setCellValueFactory(cellData -> cellData.getValue().partCostProperty().asObject());
        partTableAdd.setItems(importedParts);

    // part table (bottom)
        partIdColumnDel.setCellValueFactory(cellData -> cellData.getValue().partIdProperty().asObject());
        partNameColumnDel.setCellValueFactory(cellData -> cellData.getValue().partNameProperty());
        partInvColumnDel.setCellValueFactory(cellData -> cellData.getValue().partInvProperty().asObject());
        partCostColumnDel.setCellValueFactory(cellData -> cellData.getValue().partCostProperty().asObject());


    

    /**
     * Returns true if the user clicked OK, false otherwise.
     * 
     * @return
     */
    public boolean isSaveClicked() 
        return saveClicked;
    

    public boolean isAddClicked() 
        return addClicked;
    

    /**
     * Called when the user clicks Add.
     */
    @FXML
    private void handleAdd() 

         Part selectedPart = partTableAdd.getSelectionModel().getSelectedItem();
         if (selectedPart != null) 
             productParts.add(selectedPart);
             partTableDel.getItems().add(selectedPart);
         
        else //part not selected
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setTitle("No Selection");
            alert.setHeaderText("No part is selected");
            alert.setContentText("Please select a part from the top table.");
            alert.showAndWait();
        
     

    /**
     * Sets the stage of this dialogue
     * 
     * @param dialogueStage 
     */
    @FXML
    public void setDialogueStage(Stage dialogueStage) 
        this.dialogueStage = dialogueStage;
    

    // References MainApp
    public void setMainApp(MainApp mainApp) 
        this.mainApp = mainApp;
    

    public void setTextFields() 
        try 
            productIdField.setText(Integer.toString(Inventory.selectedProduct.getProductId()));
            productNameField.setText(Inventory.selectedProduct.getProductName());
            productInvField.setText(Integer.toString(Inventory.selectedProduct.getProductInv()));
            productCostField.setText(Double.toString(Inventory.selectedProduct.getProductCost()));
            maxField.setText(Integer.toString(Inventory.selectedProduct.getMax()));
            minField.setText(Integer.toString(Inventory.selectedProduct.getMin()));

         catch (NullPointerException e) 
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setTitle("Data Not Found");
            alert.setHeaderText("Cannot find the requested data...");
            alert.setContentText("The requested data is not being passed \n"+
                                 "correctly.  Check your code for data \n"+
                                 "flow errors. \n\n" +
                                productIdField.getText()+ "\n" +
                                productNameField.getText()+ "\n" +
                                productInvField.getText()+ "\n" +
                                productCostField.getText()+ "\n" +
                                maxField.getText()+ "\n" +
                                minField.getText());
            alert.showAndWait();
        
    

    @FXML
    public void handleSave() 

        if(isInputValid()) 

                draftProduct.setProductId(Integer.parseInt(productIdField.getText()));
                draftProduct.setProductName(productNameField.getText());
                draftProduct.setProductInv(Integer.parseInt(productInvField.getText()));
                draftProduct.setProductCost(Double.parseDouble(productCostField.getText()));
                draftProduct.setMax(Integer.parseInt(maxField.getText()));
                draftProduct.setMin(Integer.parseInt(minField.getText()));

                mainApp.getProductData().add(draftProduct);

            

            dialogueStage.close();

        


    /**
     * Called when the user clicks cancel.
     */
    @FXML
    private void handleCancel() 
        dialogueStage.close();
    

    //------------------Working code, **** DO NOT DELETE **** -----------------------------------------------
    private boolean isInputValid() 
        String errorMessage = "";

        // NO check needed for partID as it's auto-generated.

        if(productNameField.getText().isEmpty() || productNameField.getText().matches("\\d+")) 
            errorMessage += "Name: \t\t\t No valid product name!\n"
                         + "\t\t\t\t Only letters are allowed. \n\n";
        

        if(productInvField.getText().isEmpty() || !productInvField.getText().matches("\\d+")) 

            errorMessage += "Inv: \t\t\t\t No valid inventory level!\n"
                        + "\t\t\t\t Only numbers are allowed. \n\n";

             else if(productInvField.getText().compareToIgnoreCase(maxField.getText()) > 0) 
                    errorMessage += "Inv: \t\t\t\t Inv cannot exceed Max. \n\n";

             else if(productInvField.getText().compareToIgnoreCase(minField.getText()) < 0) 
                    errorMessage += "Inv: \t\t\t\t Inv cannot deceed Min. \n\n";  
        

        if(productCostField.getText().isEmpty() || !productCostField.getText().matches("\\d+\\.\\d+\\d+")) 
            errorMessage += "Price/Cost: \t\t No valid cost figures!\n"
                        + "\t\t\t\t Only numbers are allowed. \n\n";
        

        if(maxField.getText().isEmpty() || !maxField.getText().matches("\\d+")) 
                errorMessage += "Max: \t\t\t No valid maximum!\n"
                        + "\t\t\t\t Only numbers are allowed. \n\n";

             else if(maxField.getText().compareToIgnoreCase(minField.getText()) < 0) 
                errorMessage += "Max: \t\t\t Max may not deceed Min. \n\n";                        
        

        if(minField.getText().isEmpty() || !minField.getText().matches("\\d+")) 
                errorMessage += "Min: \t\t\t No valid minimum!\n"
                        + "\t\t\t\t Only numbers are allowed. \n\n";

             else if(minField.getText().compareToIgnoreCase(maxField.getText()) > 0) 
                errorMessage += "Min: \t\t\t Min may not exceed Max. \n\n";                        
        

        if(partTableAdd.getItems().isEmpty()) 
            errorMessage += "Imported Parts: \t There are currently no parts imported. \n"
                    + "\t\t\t\t There must be parts imported to select\n"
                    + "\t\t\t\t for inclusion in a new product!\n\n";
        

        if(partTableDel.getItems().isEmpty()) 
            errorMessage += "Product Parts: \t\t There are currently no parts to include. \n"
                    + "\t\t\t\t There must be parts selected to\n"
                    + "\t\t\t\t for inclusion to create a new product!\n\n";
        

        if(errorMessage.length() == 0) 
            return true;
         else 
            // Show the error message
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.initOwner(dialogueStage);
            alert.setTitle("Empty or Invalid Fields");
            alert.setHeaderText("Please correct the empty or invalid fields");
            alert.setContentText(errorMessage);

            alert.show();

            return false;
        
    
    //------------------Working code, **** DO NOT DELETE **** -----------------------------------------------

   @FXML
    public void searchImportedParts() 

        String searchItem = searchFieldModProds.getText();

        FilteredList<Part> searchPartResults = searchPartsList(searchItem);
        SortedList<Part> sortedParts = new SortedList<>(searchPartResults);
        sortedParts.comparatorProperty().bind(partTableAdd.comparatorProperty());
        partTableAdd.setItems(sortedParts);

    

    public FilteredList<Part> searchPartsList (String s) 
        return Inventory.getAllParts().filtered(p -> p.getPartName().toLowerCase().contains(s.toLowerCase()));
    

    /**
     * Called when the user clicks on the delete button.
     */
    @FXML//------------------Working code, **** DO NOT DELETE **** -----------------------------------------------
    private void handleDelete(ActionEvent e)                                                                      

        Part selectedPart;
        selectedPart = partTableDel.getSelectionModel().getSelectedItem();

        if(selectedPart != null)                                                                                  
                // Confirm deletion                                                                                    
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION);                                                 
                alert.setTitle("Confirm Deletion");                                                                    
                alert.setHeaderText("Deleting...");                                                                    
                alert.setContentText("Are you sure you want to delete the part: " + "\'" + selectedPart.getPartName() + "\'" + "?"); //
                alert.showAndWait()                                                                                    
                        .filter(response -> response  ==  ButtonType.OK)                                                 
                        .ifPresent(response -> Inventory.getDelParts().remove(selectedPart));                             

                // Update productTableMain                                                                                
                partTableDel.setItems(Inventory.getDelParts());

            else                                                           //                                       //
                // Nothing selected...                                                                                 
                Alert alert = new Alert(Alert.AlertType.WARNING);                                                      
                alert.setTitle("No selection");                                                                        
                alert.setHeaderText("No product selected");                                                               
                alert.setContentText("Please select a product in the table.");                                            
                alert.showAndWait();
                                                                                                                      
       //------------------Working code, **** DO NOT DELETE **** -------------------------------------------------         

修改Product.fxml

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jbernsd_IMS.View.ModifyProductController">
   <children>
      <Rectangle arcHeight="20.0" arcWidth="20.0" fill="TRANSPARENT"  layoutX="10.0" layoutY="10.0" stroke="#979797" strokeType="OUTSIDE" strokeWidth="2.0"  />
      <TableView fx:id="partTableAdd" layoutX="386.0" layoutY="103.0" prefHeight="108.0" prefWidth="349.0">
        <columns>
          <TableColumn prefWidth="75.0" text="Part ID:" />
          <TableColumn prefWidth="75.0" text="Part Name" />
            <TableColumn prefWidth="102.0" text="Inventory Level" />
            <TableColumn prefWidth="96.0" text="Price per Unit" />
        </columns>
      </TableView>
      <TableView fx:id="partTableDel" layoutX="386.0" layoutY="290.0" prefHeight="108.0" prefWidth="349.0">
         <columns>
            <TableColumn prefWidth="75.0" text="Part ID:" />
            <TableColumn prefWidth="75.0" text="Part Name" />
            <TableColumn prefWidth="102.0" text="Inventory Level" />
            <TableColumn prefWidth="96.0" text="Price per Unit" />
         </columns>
      </TableView>
      <Button fx:id="addBtn" layoutX="665.0" layoutY="221.0" mnemonicParsing="false" onAction="#handleAdd" prefHeight="30.0" prefWidth="70.0" text="Add">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </Button>
      <Button fx:id="delBtn" layoutX="665.0" layoutY="408.0" mnemonicParsing="false" onAction="#handleDelete" prefHeight="30.0" prefWidth="70.0" text="Delete">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font></Button>
      <Button fx:id="cancelBtn" layoutX="466.0" layoutY="446.0" mnemonicParsing="false" onAction="#handleCancel" prefHeight="30.0" prefWidth="70.0" text="Cancel">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </Button>
      <Button fx:id="saveBtn" layoutX="376.0" layoutY="446.0" mnemonicParsing="false" onAction="#handleSave" prefHeight="30.0" prefWidth="70.0" text="Save">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </Button>
      <TextField fx:id="searchFieldModProds" layoutX="536.0" layoutY="63.0" prefHeight="25.0" prefWidth="199.0">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Button fx:id="searchBtn" layoutX="456.0" layoutY="61.0" mnemonicParsing="false" onAction="#searchImportedParts" prefHeight="30.0" prefWidth="70.0" text="Search">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </Button>
      <TextField fx:id="idField" layoutX="98.0" layoutY="132.0" prefHeight="44.0" prefWidth="149.0" promptText="Auto Gen - Disabled">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelIdModProd" layoutX="29.0" layoutY="144.0" text="ID">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <TextField fx:id="nameField" layoutX="98.0" layoutY="182.0" prefHeight="44.0" prefWidth="149.0" promptText="Product Name">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelNameModProds" layoutX="29.0" layoutY="194.0" text="Name">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <TextField fx:id="invField" layoutX="98.0" layoutY="232.0" prefHeight="44.0" prefWidth="70.0" promptText="Inv">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelInvModProds" layoutX="29.0" layoutY="244.0" text="Inv">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <TextField fx:id="priceField" layoutX="98.0" layoutY="282.0" prefHeight="44.0" prefWidth="70.0" promptText="Price">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelPriceModProds" layoutX="29.0" layoutY="294.0" text="Price">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <TextField fx:id="maxField" layoutX="98.0" layoutY="332.0" prefHeight="44.0" prefWidth="70.0" promptText="Max">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelMaxModProds" layoutX="29.0" layoutY="344.0" text="Max">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <TextField fx:id="minField" layoutX="228.0" layoutY="332.0" prefHeight="44.0" prefWidth="70.0" promptText="Min">
         <font>
            <Font name="Calibri Italic" size="12.0" />
         </font>
      </TextField>
      <Label fx:id="labelMinModProds" layoutX="185.0" layoutY="344.0" text="Min">
         <font>
            <Font name="Calibri Italic" size="14.0" />
         </font>
      </Label>
      <Label fx:id="labelModifyPart" layoutX="34.0" layoutY="53.0" text="Modify Products">
         <font>
            <Font name="Calibri Bold Italic" size="24.0" />
         </font>
      </Label>
   </children>
</AnchorPane>

只需要记住匹配名称和其他标识符,并确保所有内容都指向它应该指向的其他所有内容。谢谢大家的帮助!!

【讨论】:

如果你充实了这个(也许是一个很好的部分),这甚至可能是一个答案。

以上是关于从文本字段中提取空数据。表已填充,但无法检索对象。 Java/JavaFX的主要内容,如果未能解决你的问题,请参考以下文章

无法使用光标从数据库中成功检索Spinner选定的项目文本以填充我的应用程序中的联系人列表项目

如何从 JButton 中检索数据?

如何从 Swift 中嵌入 UITableView 的文本字段中检索数据?

如何在搜索/过滤数据期间处理空字段?

用于从文本日志文件中提取/检索值的 Shell 脚本(sqlcode 字段值)

从 NSDictionary 检索数据