Captain Prinny
Captain Prinny

Reputation: 469

JavaFX: Extracting data from a TableView

I'm currently using an application that allows the user to search through given files for data they might look for, and everything works swimmingly.

The next implementation is to allow the user to populate their own data and save it to a separate file.

Since the view-area of the searched data is identical to how I would make a form for writing new data, I figured that I would just re-use the fields.

However, I have a TableView as one of the items, and I'm not certain how you extract the information from the table.

I was presuming that since the TableView is populated with a custom Row class that I could retrieve the set of Rows that make up the table and deconstruct them that way, but I cannot ascertain how this would best be done.

Concurrently, I'm trying to learn how to override elements of the TableView's cell factories to make the cells editable (because being editable doesn't do anything by default?), so that might be a place to consolidate strategy.

Upvotes: 0

Views: 2679

Answers (1)

James_D
James_D

Reputation: 209225

You just need to call getItems() on the table and iterate through the returned list. Assuming everything is set up in the normal "JavaFX way", any properties in the lists elements will be automatically updated by the editing mechanism.

Here is a complete, FXML-based example.

EditableTableExample.fxml (in package application):

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

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.cell.TextFieldTableCell?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="application.EditableTableViewController">
    <center>
        <TableView fx:id="table" editable="true">
            <columns>
                <TableColumn text="First Name" prefWidth="150"
                    fx:id="firstNameColumn">
                    <cellFactory>
                        <TextFieldTableCell fx:factory="forTableColumn" />
                    </cellFactory>
                </TableColumn>
                <TableColumn text="Last Name" prefWidth="150" fx:id="lastNameColumn">
                    <cellFactory>
                        <TextFieldTableCell fx:factory="forTableColumn" />
                    </cellFactory>
                </TableColumn>
                <TableColumn text="Email" prefWidth="150" fx:id="emailColumn">
                    <cellFactory>
                        <TextFieldTableCell fx:factory="forTableColumn" />
                    </cellFactory>
                </TableColumn>
            </columns>
        </TableView>
    </center>
    <bottom>
        <HBox alignment="CENTER">
            <padding>
                <Insets top="10" right="10" left="10" bottom="10" />
            </padding>
            <children>
                <Button onAction="#showData" text="Show Data" />
            </children>
        </HBox>
    </bottom>
</BorderPane>

EditableTableController:

package application;

import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;


public class EditableTableViewController {

    @FXML
    private TableView<Person> table ;

    @FXML
    private TableColumn<Person, String> firstNameColumn ;

    @FXML
    private TableColumn<Person, String> lastNameColumn ;

    @FXML
    private TableColumn<Person, String> emailColumn ;

    public void initialize() {
        firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
        lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
        emailColumn.setCellValueFactory(cellData -> cellData.getValue().emailProperty());

        table.getItems().addAll(
                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 showData() {
        for (Person person : table.getItems()) {
            String formatted = String.format("%s %s (%s)", person.getFirstName(), person.getLastName(), person.getEmail());
            System.out.println(formatted);
        }
        System.out.println();
    }
}

Model class Person:

package application;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
    public final String getFirstName() {
        return firstNameProperty().get();
    }
    public final void setFirstName(String firstName) {
        firstNameProperty().set(firstName);
    }
    public StringProperty firstNameProperty() {
        return firstName ;
    }

    private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
    public final String getLastName() {
        return lastNameProperty().get();
    }
    public final void setLastName(String lastName) {
        lastNameProperty().set(lastName);
    }
    public StringProperty lastNameProperty() {
        return lastName ;
    }

    private final StringProperty email = new SimpleStringProperty(this, "email");
    public final String getEmail() {
        return emailProperty().get();
    }
    public final void setEmail(String email) {
        emailProperty().set(email);
    }
    public StringProperty emailProperty() {
        return email ;
    }

    public Person(String firstName, String lastName, String email) {
        this.setFirstName(firstName);
        this.setLastName(lastName);
        this.setEmail(email);
    }
}

Application class:

package application;

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


public class EditableTableViewExample extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("EditableTableExample.fxml"));
        BorderPane root = loader.load();
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);       
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

The button is just for demonstration, but pressing it will invoke the showData() method in the controller, which iterates through the table's list of items and retrieves the property values from each one. If you double-click a cell to edit, type to change the value, and then commit the edit with Enter, then pressing the button will show the updated values.

Upvotes: 2

Related Questions