Can't populate JavaFX TableView created in SceneBuilder 2

16,699

Solution 1

You haven't set any cellValueFactorys on your TableColumns (Example 12-5 in the tutorial you linked).

You can do this in FXML with

<TableColumn fx:id="firstNameCol" prefWidth="75.0" text="First Name" >
    <cellValueFactory><PropertyValueFactory property="firstName"/></cellValueFactory>
</TableColumn>

or in the controller with

firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName"));

(and similarly for the other columns)

Solution 2

You've actually made two mistakes.

First of all, you're trying to assign the datamodel to the TableView using getItems().setAll(). Take a look at the documentation of setAll(). It copies all the values of the given list into the ObservableList. This is not what you want, you want the TableView to start observing data and responding to changes. The way to do this is to assign a reference directly, through setItems(data).

Take a look at the code examples in the documentation of TableView. You forgot to connect the various StringProperties in Person up to the columns. This is the way they do it:

firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

Lastly, I've got a little sidenote. Note that this is NOT the cause of your specific issue.

I see you're using raw types. This is generally considered a bad thing, and you're probably getting some warnings from the compiler about it. You can solve the issue by stating the generic types your objects use. Notice in the above code sample, I state for the PropertyValueFactories that the type of class contained within the TableView.items is Person and that the type of object displayed in the rows is String.

As for scrolling, which you also asked for, it does that automatically once there are enough lines in the TableView.

Share:
16,699
Gary
Author by

Gary

Updated on June 28, 2022

Comments

  • Gary
    Gary almost 2 years

    I am trying to re-create the table view sample using scene builder 2, but my TableView couldn’t be populated.

    I defined my table in JavaFx SceneBuilder like so:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane id="AnchorPane" prefHeight="380.0" prefWidth="462.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="tableviewsample.FXMLDocumentController">
        <children>
            <Button fx:id="button" layoutX="325.0" layoutY="324.0" onAction="#handleButtonAction" text="Click Me!" />
            <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
            <TableView fx:id="table" layoutX="26.0" layoutY="29.0" prefHeight="221.0" prefWidth="411.0">
                <columns>
                    <TableColumn fx:id="firstNameCol" prefWidth="75.0" text="First Name" />
                    <TableColumn fx:id="lastNameCol" prefWidth="75.0" text="Last Name" />
                    <TableColumn fx:id="emailCol" prefWidth="75.0" text="Email" />
                </columns>
            </TableView>
            <TextField fx:id="addFirstName" layoutX="26.0" layoutY="284.0" prefHeight="25.0" prefWidth="81.0" promptText="First Name" />
            <TextField fx:id="addLastName" layoutX="121.0" layoutY="284.0" prefHeight="25.0" prefWidth="89.0" promptText="Last Name" />
            <TextField fx:id="addEmail" layoutX="222.0" layoutY="284.0" promptText="Email" />
        </children>
    </AnchorPane>
    

    My controller code:

    package tableviewsample;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    
    public class FXMLDocumentController implements Initializable {
    
        @FXML
        private Label label;
    
        @FXML
        private TableView<Person> table;// = new TableView<Person>();
    
        @FXML private TableColumn firstNameCol ;
        @FXML private TableColumn lastNameCol ;
        @FXML private TableColumn emailCol ;
    
        @FXML TextField addFirstName;
        @FXML TextField addLastName;
        @FXML TextField addEmail;
    
        private final ObservableList<Person> data
                = FXCollections.observableArrayList(
                        new Person("Jacob", "Smith", "[email protected]"),
                        new Person("Isabella", "Johnson", "[email protected]"),
                        new Person("Ethan", "Williams", "[email protected]"),
                        new Person("Emma", "Jones", "[email protected]"),
                        new Person("Michael", "Brown", "[email protected]")
                );
    
        @FXML
        private void handleButtonAction(ActionEvent event) {
            System.out.println("You clicked me!");
            data.add(new Person(
                    addFirstName.getText(),
                    addLastName.getText(),
                    addEmail.getText()));
            addFirstName.clear();
            addLastName.clear();
            addEmail.clear();
        }
    
        @Override
        public void initialize(URL url, ResourceBundle rb) {
            // TODO
            firstNameCol.setMinWidth(100);
            lastNameCol.setMinWidth(100);
            emailCol.setMinWidth(200);
            table.getItems().setAll(this.data);
        }
    
        public static class Person {
    
            private final SimpleStringProperty firstName;
            private final SimpleStringProperty lastName;
            private final SimpleStringProperty email;
    
            private Person(String fName, String lName, String email) {
                this.firstName = new SimpleStringProperty(fName);
                this.lastName = new SimpleStringProperty(lName);
                this.email = new SimpleStringProperty(email);
            }
    
            public String getFirstName() {
                return firstName.get();
            }
    
            public void setFirstName(String fName) {
                firstName.set(fName);
            }
    
            public String getLastName() {
                return lastName.get();
            }
    
            public void setLastName(String fName) {
                lastName.set(fName);
            }
    
            public String getEmail() {
                return email.get();
            }
    
            public void setEmail(String fName) {
                email.set(fName);
            }
        }
    }
    

    The main code:

    package tableviewsample;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class TableViewSample extends Application {
    
        @Override
        public void start(Stage stage) throws Exception {
            Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    Screenshot:

    screenshot

    When I run it, there are empty rows in the table. If I type some values in the 3 TextFields and click the button, still the values are not inserted in the table. Can you please find what's wrong with the code? Also, on an unrelated note, how can I make the table scrollable?

  • Gary
    Gary over 9 years
    @Janes. Thanks. I set cellValueFactorys for the table columns inside the initilize method, the table is populated when I run it. now, the button still can't add new rows to the table. any idea? thanks again!
  • James_D
    James_D over 9 years
    Either see A Boschman's answer, or do table.getItems().add(...) in the button handler, instead of data.add(...)
  • Gary
    Gary over 9 years
    @A. Thanks for finding that misktake for me!!!!, I changed to table.setItems(this.data) as you suggested, my button can add rows to the table!. James found the other mistake for me. both of you gave me great help, I stuck on this for almost 1day.