Search code examples
javafxtableviewobservablelist

JavaFx TableView (TV) with ObservableList (OL): How to edit the TV and update the OL automatically


I am using an ObservableList which is attached to a TableView. Now first of all I want to make the TableView editable and then when specific fields get edited, I want to update the corresponding object in the ObservableList. But somehow I struggle with getting the updated value from the TableView. And if I use

tv_column.setCellFactory(TextFieldTableCell.forTableColumn());

then I get the error:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

My Cell Value Factory:

tv_column.setCellValueFactory(new PropertyValueFactory<SaleItem,Double>("quantity"));

Models:

public interface SaleItem {
    void setProductName(String productName);
    void setPrice(double price);
    double getPrice();
    double getTotalPrice();
    void setTotalPrice();
    String getProductCode();
    String getProductCodeDescription();
    String getDescription();
    String getProductName();
}

public abstract class NonFuel implements SaleItem {
    public SimpleIntegerProperty quantity = new SimpleIntegerProperty();
    public SimpleDoubleProperty price = new SimpleDoubleProperty(0.0);
    public SimpleStringProperty productName = new SimpleStringProperty("");
    SimpleDoubleProperty totalPrice = new SimpleDoubleProperty(0.0);
    // getter and setter
}

public class Drinks extends NonFuel {
    public Drinks() {
        setProductName("Coffee");
        setPrice(2.20);
        setQuantity(1);
    }
    // getter and setter
}

Can somebody help getting the new Value from the TV or updating the OL behind it?

Thanks in advance.


Solution

  • I figured out that there were two problems:

    1. The double or integer Value from my Model needed to be converted to and from string. I can configure this directly in the column:

      tv_column.setCellFactory(
          TextFieldTableCell.forTableColumn(
              new StringConverter<Double>() {
                  @Override
                  public String toString(Double object) {
                      return Double.toString(object);
                  }
      
                  @Override
                  public Double fromString(String string) {
                      return Double.valueOf(string);
                  }
              }
          )
      );
      
    2. On the other hand I had to get the event of editing the cell and give the new value to the Item of the ObservableList. Then I had to update the item and refresh the TableView:

      tv_column.setOnEditCommit(
          new EventHandler<TableColumn.CellEditEvent<SaleItem, Double>>() {
              @Override
              public void handle(TableColumn.CellEditEvent<SaleItem, Double> event) {
                  SaleItem saleItem =  event.getTableView().getItems().get(event.getTablePosition().getRow());
                  saleItem.setQuantity(event.getNewValue());
                  saleItem.updatePrice();
                  tv.refresh();
              }
          }
      );