You can take advantage of the power of JavaFX up to bind .
A few points to follow when implementing the scenario, as described above:
- POJO fields (in your case
Data ) must have the correct types. For example, price and quantity should be SimpleIntegerProperty instead of SimpleStringProperty . This will help us use Bindings . Field SubTotal depends on the price and quantity. The best way to achieve this is to bind subTotalProperty to a multiply Binding of price and quantity .
I created a (not so) simple example of a basic editable table view to show this approach. It has additional features, such as editable cells, that you (or others looking for the same problem) may need;)
import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.binding.NumberBinding; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.TableColumn.CellEditEvent; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage; import javafx.util.converter.NumberStringConverter; public class TableViewSample extends Application { private TableView<Product> table = new TableView<Product>(); private final ObservableList<Product> data = FXCollections.observableArrayList( new Product("Notebook", 10, 12), new Product("Eraser", 20, 12), new Product("Pencil", 30, 12), new Product("Pen", 40, 12), new Product("Glue", 50, 12)); final HBox hb = new HBox(); public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) { Scene scene = new Scene(new Group()); stage.setTitle("Book Store Sample"); stage.setWidth(650); stage.setHeight(550); final Label label = new Label("Book Store"); label.setFont(new Font("Arial", 20)); table.setEditable(true); TableColumn name = new TableColumn("Name"); name.setMinWidth(100); name.setCellValueFactory( new PropertyValueFactory<Product, String>("name")); name.setCellFactory(TextFieldTableCell.forTableColumn()); name.setOnEditCommit( new EventHandler<CellEditEvent<Product, String>>() { @Override public void handle(CellEditEvent<Product, String> t) { ((Product) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setName(t.getNewValue()); } } ); TableColumn priceCol = new TableColumn("Price"); priceCol.setMinWidth(100); priceCol.setCellValueFactory( new PropertyValueFactory<Product, String>("price")); priceCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter())); priceCol.setOnEditCommit( new EventHandler<CellEditEvent<Product, Number>>() { @Override public void handle(CellEditEvent<Product, Number> t) { ((Product) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setPrice(t.getNewValue().intValue()); } } ); TableColumn quantityCol = new TableColumn("Quantity"); quantityCol.setMinWidth(200); quantityCol.setCellValueFactory( new PropertyValueFactory<Product, Number>("quantity")); quantityCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter())); quantityCol.setOnEditCommit( new EventHandler<CellEditEvent<Product, Number>>() { @Override public void handle(CellEditEvent<Product, Number> t) { ((Product) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setQuantity(t.getNewValue().intValue()); } } ); TableColumn subTotalCol = new TableColumn("Sub Total"); subTotalCol.setMinWidth(200); subTotalCol.setCellValueFactory( new PropertyValueFactory<Product, String>("subTotal")); table.setItems(data); table.getColumns().addAll(name, priceCol, quantityCol, subTotalCol); final TextField addName = new TextField(); addName.setPromptText("Name"); addName.setMaxWidth(name.getPrefWidth()); final TextField addPrice = new TextField(); addPrice.setMaxWidth(priceCol.getPrefWidth()); addPrice.setPromptText("Price"); final TextField addQuantity = new TextField(); addQuantity.setMaxWidth(quantityCol.getPrefWidth()); addQuantity.setPromptText("Quantity"); final Button addButton = new Button("Add"); addButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { data.add(new Product( name.getText(), Integer.parseInt(addPrice.getText()), Integer.parseInt(addQuantity.getText()))); addName.clear(); addPrice.clear(); addQuantity.clear(); } }); hb.getChildren().addAll(addName, addPrice, addQuantity, addButton); hb.setSpacing(3); final VBox vbox = new VBox(); vbox.setSpacing(5); vbox.setPadding(new Insets(10, 0, 0, 10)); vbox.getChildren().addAll(label, table, hb); ((Group) scene.getRoot()).getChildren().addAll(vbox); stage.setScene(scene); stage.show(); } public static class Product { private final SimpleStringProperty name; private final SimpleIntegerProperty price; private final SimpleIntegerProperty quantity; private final SimpleIntegerProperty subTotal; private Product(String name, int price, int quantity) { this.name = new SimpleStringProperty(name); this.price = new SimpleIntegerProperty(price); this.quantity = new SimpleIntegerProperty(quantity); this.subTotal = new SimpleIntegerProperty(); NumberBinding multiplication = Bindings.multiply(this.priceProperty(), this.quantityProperty()); this.subTotalProperty().bind(multiplication); } public String getName() { return name.get(); } public SimpleStringProperty nameProperty() { return name; } public void setName(String name) { this.name.set(name); } public int getPrice() { return price.get(); } public SimpleIntegerProperty priceProperty() { return price; } public void setPrice(int price) { this.price.set(price); } public int getQuantity() { return quantity.get(); } public SimpleIntegerProperty quantityProperty() { return quantity; } public void setQuantity(int quantity) { this.quantity.set(quantity); } public int getSubTotal() { return subTotal.get(); } public SimpleIntegerProperty subTotalProperty() { return subTotal; } public void setSubTotal(int subTotal) { this.subTotal.set(subTotal); } } }
Screenshot

Note I defined setCellFactory and setOnCommit for each column. This is because the columns of the name, price and quantity are editable . You can delete them if you are not looking for an editable property.