javafx TableView Sample TableView with 2 columns


Table Item

The following class contains 2 properties a name (String) and the size (double). Both properties are wrapped in JavaFX properties to allow the TableView to observe changes.


public class Person {
    public Person(String name, double size) {
        this.size = new SimpleDoubleProperty(this, "size", size); = new SimpleStringProperty(this, "name", name);
    private final StringProperty name;
    private final DoubleProperty size;

    public final String getName() {

    public final void setName(String value) {;

    public final StringProperty nameProperty() {

    public final double getSize() {
        return this.size.get();

    public final void setSize(double value) {

    public final DoubleProperty sizeProperty() {
        return this.size;


Sample Application

This application shows a TableView with 2 columns; one for the name and one for the size of a Person. Selecting one of the Persons adds the data to TextFields below the TableView and allow the user to edit the data. Note once the edit is commited, the TableView is automatically updated.

To every for every TableColumn added to the TableView a cellValueFactory is assigned. This factory is responsible for converting table items (Persons) to ObservableValues that contain the value that should be displayed in the table cell and that allows the TableView to listen to any changes for this value.

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
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.TextFormatter;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;

public class TableSample extends Application {

    public void start(Stage primaryStage) {
        // data for the tableview. modifying this list automatically updates the tableview
        ObservableList<Person> data = FXCollections.observableArrayList(
                new Person("John Doe", 1.75),
                new Person("Mary Miller", 1.70),
                new Person("Frank Smith", 1.80),
                new Person("Charlotte Hoffman", 1.80)

        TableView<Person> tableView = new TableView<>(data);

        // table column for the name of the person
        TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
        nameColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>>() {

            public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> param) {
                return param.getValue().nameProperty();

        // column for the size of the person
        TableColumn<Person, Number> sizeColumn = new TableColumn<>("Size");
        sizeColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, Number>, ObservableValue<Number>>() {

            public ObservableValue<Number> call(TableColumn.CellDataFeatures<Person, Number> param) {
                return param.getValue().sizeProperty();

        // add columns to tableview
        tableView.getColumns().addAll(nameColumn, sizeColumn);

        TextField name = new TextField();

        TextField size = new TextField();

        // convert input from textfield to double
        TextFormatter<Double> sizeFormatter = new TextFormatter<Double>(new StringConverter<Double>() {

            public String toString(Double object) {
                return object == null ? "" : object.toString();

            public Double fromString(String string) {
                if (string == null || string.isEmpty()) {
                    return null;
                } else {
                    try {
                        double val = Double.parseDouble(string);
                        return val < 0 ? null : val;
                    } catch (NumberFormatException ex) {
                        return null;


        Button commit = new Button("Change Item");
        commit.setOnAction(new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                Person p = tableView.getSelectionModel().getSelectedItem();
                Double value = sizeFormatter.getValue();
                p.setSize(value == null ? -1d : value);


        // listen for changes in the selection to update the data in the textfields
        tableView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {

            public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
                commit.setDisable(newValue == null);
                if (newValue != null) {


        HBox editors = new HBox(5, new Label("Name:"), name, new Label("Size: "), size, commit);

        VBox root = new VBox(10, tableView, editors);

        Scene scene = new Scene(root);


    public static void main(String[] args) {