0

I'm having issues showing new additions to a class in a TableView for my JavaFX/FXML program. I've looked at countless tutorials but the missing piece still escapes me.

I had some errors that got fixed here: JavaFX Adding Rows to TableView on Different Page

And then found a new tutorial to sort of follow that explained things a bit better than the first one I was following (their app is a bit different than what I have to do) here: http://code.makery.ch/library/javafx-8-tutorial/part2/

I have an output printing the name field out to the console just to make sure it is pulling the right values from the add form. I also changed the way I navigated between Add Part and the Main window (nothing else works right now). I feel so silly asking this, but Java is the one language I haven't been able to wrap my head around.

Any ideas on why it isn't updating are greatly appreciated.

IMS.java

package ims;

import java.io.IOException;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 *
 * @author chelseacamper
 */
public class IMS extends Application {
    private Stage primaryStage;
    private BorderPane rootLayout;

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

    public IMS() {
        partData.add(new Part("Part A", 3, 4.00, 1, 5));
        partData.add(new Part("Part B", 2, 14.00, 1, 15));
    }

    public ObservableList<Part> getPartData(){
        return partData;
    }

    @Override
    public void start(Stage stage) throws Exception {

//        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        Parent root = (Parent) loader.load();
        FXMLDocumentController ctrl = loader.getController();
        ctrl.setMainApp(this);
        Scene scene = new Scene(root);
        scene.getStylesheets().add("style.css");
        stage.setScene(scene);
        stage.show();

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

FXMLDocumentController.java

package ims;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

/**
 *
 * @author chelseacamper
 */
public class FXMLDocumentController implements Initializable {

    @FXML
    private Label label;
    @FXML
    private TableView<Part> partTable;
    @FXML
    private TableColumn<Part, Integer> partIDColumn;
    @FXML
    private TableColumn<Part, String> nameColumn;
    @FXML
    private TableColumn<Part, Integer> inventoryColumn;
    @FXML
    private TableColumn<Part, Double> priceColumn;

    private IMS mainApp;

    public FXMLDocumentController(){

    }

    @FXML
    private void addPart(ActionEvent event) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("addPart.fxml"));
        Parent add_part_parent = (Parent) loader.load();
        Stage stage = new Stage();
        stage.setScene(new Scene(add_part_parent));
        stage.show();
    }

    @FXML
    private void modifyPart(ActionEvent event) throws IOException {
        Parent modify_part_parent = FXMLLoader.load(getClass().getResource("modifyPart.fxml"));
        Scene modify_part_scene = new Scene(modify_part_parent);
        modify_part_scene.getStylesheets().add("style.css");
        Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        app_stage.setScene(modify_part_scene);
        app_stage.show();
    }

    @FXML
    private void addProduct(ActionEvent event) throws IOException {
        Parent add_product_parent = FXMLLoader.load(getClass().getResource("addProduct.fxml"));
        Scene add_product_scene = new Scene(add_product_parent);
        add_product_scene.getStylesheets().add("style.css");
        Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        app_stage.setScene(add_product_scene);
        app_stage.show();
    }

    @FXML
    private void modifyProduct(ActionEvent event) throws IOException {
        Parent modify_product_parent = FXMLLoader.load(getClass().getResource("modifyProduct.fxml"));
        Scene modify_product_scene = new Scene(modify_product_parent);
        modify_product_scene.getStylesheets().add("style.css");
        Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        app_stage.setScene(modify_product_scene);
        app_stage.show();
    }    

    @FXML
    private void closeProgram(ActionEvent event) throws IOException {
        Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        app_stage.close();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
//        nameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
//        inventoryColumn.setCellValueFactory(cellData -> cellData.getValue().instockProperty().asObject());
//        priceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty().asObject());

        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        inventoryColumn.setCellValueFactory(new PropertyValueFactory<>("instock"));
        priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));

    }

    public void setMainApp(IMS mainApp) {
        this.mainApp = mainApp;

        // Add observable list data to the table
        partTable.setItems(mainApp.getPartData());
    }

    @FXML
    private void handleDeletePart(){
        int selectedIndex = partTable.getSelectionModel().getSelectedIndex();
        if (selectedIndex >= 0){
            partTable.getItems().remove(selectedIndex);
        } else {
            Alert alert = new Alert(AlertType.WARNING);
            alert.setTitle("No Part Selected");
            alert.setHeaderText("No Part Selected");
            alert.setContentText("Please select the part you would like to delete.");

            alert.showAndWait();
        }
    }
}

FXMLDocument.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.cell.*?> 
<?import javafx.collections.*?>
<?import fxmltableview.*?>
<?import ims.Part?> 
<?import ims.Inhouse?> 
<?import ims.Outsourced?> 

<BorderPane id="main" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ims.FXMLDocumentController" >
    <top>
        <Label fx:id="mainTitle" text="Inventory Management System" /> 
    </top>
    <center>
        <HBox fx:id="holding">
            <children>
                <VBox styleClass="contentBox">
                    <children>
                        <HBox styleClass="topBox">
                            <HBox styleClass="subHeading">
                                <Label text="Parts" />
                            </HBox>
                            <HBox styleClass="searchBox">
                                <Button text="Search" />
                                <TextField />
                            </HBox>
                        </HBox>
                        <TableView fx:id="partTable" styleClass="dataTable">
                            <columns>
                                <TableColumn fx:id="partIDColumn" text="Part ID" />
                                <TableColumn fx:id="nameColumn" text="Part Name" />
                                <TableColumn fx:id="inventoryColumn" text="Inventory Level" />
                                <TableColumn fx:id="priceColumn" text="Price/Cost per Unit" />
                            </columns>
                        </TableView>
                        <HBox styleClass="modificationButtons">
                            <children>
                                <Button onAction="#addPart" text="Add" /> 
                                <Button onAction="#modifyPart" text="Modify" /> 
                                <Button text="Delete" /> 
                            </children>
                        </HBox>
                    </children>
                </VBox>
                <VBox styleClass="contentBox">
                    <children>
                        <HBox styleClass="topBox">
                            <HBox styleClass="subHeading">
                                <Label text="Products" />
                            </HBox>
                            <HBox styleClass="searchBox">
                                <Button text="Search" />
                                <TextField />
                            </HBox>
                        </HBox>
                        <TableView fx:id="productTable" styleClass="dataTable">
                            <columns>
                                <TableColumn text="Part ID" />
                                <TableColumn text="Part Name" />
                                <TableColumn text="Inventory Level" />
                                <TableColumn text="Price/Cost per Unit" />
                            </columns>
                        </TableView>
                        <HBox styleClass="modificationButtons">
                            <children>
                                <Button onAction="#addProduct" text="Add" /> 
                                <Button onAction="#modifyProduct" text="Modify" /> 
                                <Button text="Delete" /> 
                            </children>
                        </HBox>
                    </children>
                </VBox>
            </children>
        </HBox>
    </center>
    <bottom>
        <HBox fx:id="exitButton">
            <children>
                <Button onAction="#closeProgram" text="Exit" />
            </children>
        </HBox>
    </bottom>
</BorderPane>

Part.java

package ims;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
 *
 * @author chelseacamper
 */
public class Part {

    private final SimpleStringProperty name;
    private final SimpleIntegerProperty instock;
    private final SimpleDoubleProperty price;
    private final SimpleIntegerProperty min;
    private final SimpleIntegerProperty max;


    public Part(){
        this("", 0, 0.00, 0, 0);

    }

    public Part(String name, int instock, double price, int min, int max) {
        this.name = new SimpleStringProperty(name);
        this.instock = new SimpleIntegerProperty(instock);
        this.price = new SimpleDoubleProperty(price);
        this.min = new SimpleIntegerProperty(min);
        this.max = new SimpleIntegerProperty(max);
    }

    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public StringProperty nameProperty() {
        return name;
    }

    public Double getPrice() {
        return price.get();
    }

    public void setPrice(Double price) {
        this.price.set(price);
    }

    public DoubleProperty priceProperty(){
        return price;
    }

    public int getInstock() {
        return instock.get();
    }

    public void setInstock(int instock) {
        this.instock.set(instock);
    }

    public IntegerProperty instockProperty(){
        return instock;
    }

    public int getMin() {
        return min.get();
    }

    public void setMin(int min) {
        this.min.set(min);
    }

    public IntegerProperty minProperty(){
        return min;
    }

    public int getMax() {
        return max.get();
    }

    public void setMax(int max) {
        this.max.set(max);
    }

    public IntegerProperty maxProperty(){
        return max;
    }
}

addPartController.java

package ims;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.stage.Stage;

/**
 * FXML Controller class
 *
 * @author chelseacamper
 */
public class AddPartController implements Initializable {
    @FXML
    ToggleButton inhouse;
    @FXML
    ToggleButton outsourced;
    @FXML
    Label inhouseLabel;
    @FXML
    Label outsourcedLabel;
    @FXML
    TextField inhouseTextField;
    @FXML
    TextField outsourcedTextField;
    @FXML
    private TableView<Part> partTable;
    @FXML
    private TextField partNameField;
    @FXML
    private TextField partInstockField;
    @FXML
    private TextField partPriceField;
    @FXML
    private TextField partMaxField;
    @FXML
    private TextField partMinField;
    @FXML
    private Button cancel;
    @FXML
    private Button save;

    private Part part = new Part();
//    private ObservableList<Part> partData = FXCollections.observableArrayList();
    private ObservableList<Part> tableItems;

    /**
     * Initializes the controller class.
     * @param url
     * @param rb
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        inhouseLabel.visibleProperty().bind( inhouse.selectedProperty() );
        outsourcedLabel.visibleProperty().bind( outsourced.selectedProperty() );
        inhouseTextField.visibleProperty().bind( inhouse.selectedProperty() );
        outsourcedTextField.visibleProperty().bind( outsourced.selectedProperty() );
        inhouseLabel.managedProperty().bind( inhouse.selectedProperty() );
        outsourcedLabel.managedProperty().bind( outsourced.selectedProperty() );
        inhouseTextField.managedProperty().bind( inhouse.selectedProperty() );
        outsourcedTextField.managedProperty().bind( outsourced.selectedProperty() );

    }

    @FXML
    public void addInhouse(ActionEvent event) throws IOException{
//        Part tempPart = new Part(partNameField.getText(),
//                Integer.parseInt(partInstockField.getText()),
//                Double.parseDouble(partPriceField.getText()),
//                Integer.parseInt(partMaxField.getText()),
//                Integer.parseInt(partMinField.getText()));


//        tableItems.add(new Part(partNameField.getText(),
//                Integer.parseInt(partInstockField.getText()),
//                Double.parseDouble(partPriceField.getText()),
//                Integer.parseInt(partMaxField.getText()),
//                Integer.parseInt(partMinField.getText())
//        ));

        part
                .setName(partNameField.getText());
        part.setPrice(Double.parseDouble(partPriceField.getText()));
        part.setInstock(Integer.parseInt(partInstockField.getText()));
        part.setMin(Integer.parseInt(partMinField.getText()));
        part.setMax(Integer.parseInt(partMaxField.getText()));

        System.out.println(partNameField.getText());

        Stage stage = (Stage) cancel.getScene().getWindow();
        stage.close();
    }

    @FXML
    private void close(ActionEvent event) throws IOException {
        Stage stage = (Stage) cancel.getScene().getWindow();
        stage.close();
    }

    void setTableItems(ObservableList<Part> tableItems) {
       this.tableItems = tableItems;
    }

}

addPart.fxml

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

<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane id="addPage" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ims.AddPartController">
    <stylesheets>
        <String fx:value="style.css" />
    </stylesheets>
    <fx:define>
        <ToggleGroup fx:id="inOutGroup" />
    </fx:define>
    <center>
        <VBox fx:id="verticalHolding">
            <children>
                <HBox fx:id="topRow">
                    <Label text="Add Part"/>
                    <RadioButton fx:id="inhouse" toggleGroup="$inOutGroup" text="In-House"/>
                    <RadioButton fx:id="outsourced" toggleGroup="$inOutGroup" selected="true" text="Outsourced"/>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label text="ID" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField promptText="Auto Gen - Disabled" disable="true" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label text="Name" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField fx:id="partNameField" promptText="Part Name" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label text="Inv" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField fx:id="partInstockField" promptText="Inv" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label text="Price/Cost" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField fx:id="partPriceField" promptText="Price/Cost" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label text="Max" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField styleClass="smallTextField" fx:id="partMaxField" promptText="Max" />
                        <Label text="Min" />
                        <TextField styleClass="smallTextField" fx:id="partMinField" promptText="Min" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                        <Label fx:id="inhouseLabel" text="Machine ID" />
                        <Label fx:id="outsourcedLabel" text="Company Name" />
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <TextField fx:id="inhouseTextField" promptText="Mach ID" />
                        <TextField fx:id="outsourcedTextField" promptText="Comp Nm" />
                    </HBox>
                </HBox>
                <HBox styleClass="fullWidth">
                    <HBox styleClass="halfWidthLeft">
                    </HBox>
                    <HBox styleClass="halfWidthRight">
                        <Button onAction="#addInhouse" fx:id="save" text="Save" />
                        <Button onAction="#close" fx:id="cancel" text="Cancel" />
                    </HBox>
                </HBox>
            </children>
        </VBox>
    </center>
</BorderPane>
Community
  • 1
  • 1
Chelsea
  • 335
  • 2
  • 13
  • In your [previous question](http://stackoverflow.com/questions/42380493/javafx-adding-rows-to-tableview-on-different-page/42380704) the solution was to pass the relevant data to the other controller, so you could modify the data. When you modify the data backing the tableview, the tableview automatically updates. In this code, you have regressed back to where you were previously: you are not passing any data to the other controllers. – James_D Feb 24 '17 at 02:26
  • Ugggggghhhh, I have tried too many things that I'm going backwards now. So this is the part that sends the table view data to the addPartController: `AddPartController addPartController = loader.getController(); addPartController.setTableItems(partTable.getItems());` but what sends it back to the main java file to update the table? – Chelsea Feb 24 '17 at 03:56
  • You don't need to send it back. It *is* the data underlying the table. If you add something to it, the table updates. Have a look at http://stackoverflow.com/questions/32342864/applying-mvc-with-javafx (the only real difference there is that the data is wrapped up in another class, but the principle is the same - share the same data between multiple controllers). – James_D Feb 24 '17 at 04:24
  • Why are you writing code in the IMS.java file? If you are going to use the fxml and controllers do not modify/Write any code in your IMS.Java or main File. – SedJ601 Feb 24 '17 at 05:34
  • I suggest you start here. http://www.java2s.com/Tutorials/Java/JavaFX/0650__JavaFX_TableView.htm They do not used Model-View-Controller framework but it's a start. They do all of the logic and gui in main class – SedJ601 Feb 24 '17 at 05:42
  • 1
    @SedrickJefferson I would think that "They do all of the logic and gui in main class" is exactly the reason you **shouldn't** use that tutorial. – James_D Feb 24 '17 at 15:27
  • I was thinking that it would help the user get a basic understanding of tableview before trying it in a MVC framework. – SedJ601 Feb 24 '17 at 15:34
  • @SedrickJefferson The OP seems to be able to use a `TableView` just fine. What she's asking about is accessing the table data from different controllers. I don't see how a tutorial that has a single class with hundreds of lines in a start method is going to be any help. – James_D Feb 24 '17 at 15:55
  • @Chelsea I recommend you simplify this. Maybe try to write a version of the `Person` table with just a couple of columns, using FXML and a controller for the main display, and another FXML/controller for adding a new person to the table. And nothing more than that. That will make it easier for you to see the structures and easier for people to help as there will be less code to wade through. – James_D Feb 24 '17 at 15:57
  • Sorry, I missed that part. I am way off. lol – SedJ601 Feb 24 '17 at 16:00
  • I am still stuck on why the user wants to have the data available in the main Class? – SedJ601 Feb 24 '17 at 16:05
  • @James_D Thanks, I will try that. – Chelsea Feb 24 '17 at 21:17
  • @SedrickJefferson I'm desperate and trying a bunch of different things. – Chelsea Feb 24 '17 at 21:17
  • @Chelsea What is the reason that you need to be able to manipulate the TableView in the Main class? – SedJ601 Feb 24 '17 at 22:14

0 Answers0