title: javafx trigger calculation across classes with bindings
body: <p>I'm a bit stuck, and maybe someone can help. I want to have a &quot;grand total&quot; calculated whenever certain fields are changed.</p>
  <p>I've made a prototype in excel to illustrate:</p>
  <p><a href="https://i.stack.imgur.com/5goOr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5goOr.png" alt="Mockup of two tables, Products and Summary" /></a></p>
  <p>So whenever a price or quantity is changed, the total cost is recalculated, and the summary should also be updated, including the &quot;Final Total&quot;. I have employed bindings and they aren't working, except when the summary items are first created, and subsequently the finalTotal field won't recalculate.</p>
  <p>I have two classes, one called Product, which contains the properties <code>productName</code>, <code>priceEach</code>, <code>quantity</code>, <code>productTotal</code>. Whenever the <code>priceEach</code> or <code>quantity</code> properties are set, a <code>calculateTotal()</code> method is called to update <code>productTotal</code>.
  Here's the code:</p>
  <pre><code>import javafx.beans.property.*;
  import javafx.beans.property.SimpleFloatProperty;
  import javafx.beans.property.StringProperty;
  
  public class Product {
     private final StringProperty productName;
     private final FloatProperty priceEach;
     private final IntegerProperty quantity;
     private  FloatProperty productTotal;
  
     public Product(){
        this.productName = new SimpleStringProperty(&quot;Product Name&quot;);
        this.priceEach = new SimpleFloatProperty(0);
        this.quantity = new SimpleIntegerProperty(0);
        this.productTotal = new SimpleFloatProperty(0);
     }
  
     public Product(String name, float priceEach, int quantity){
        this.productName = new SimpleStringProperty(name);
        this.priceEach = new SimpleFloatProperty(priceEach);
        this.quantity = new SimpleIntegerProperty(quantity);
        this.productTotal = calculateProductTotal();
     }
  
     private FloatProperty calculateProductTotal() {
        return new SimpleFloatProperty(priceEach.get()*quantity.get());
     }
  
     public void setProductName(String name){
        productName.set(name);
     }
  
     public void setPriceEach(float price){
        priceEach.set(price);
        productTotal = calculateProductTotal();
     }
  
     public void setQuantity(int number){
        quantity.set(number);
        productTotal = calculateProductTotal();
     }
  
     public String getProductName(){ return productName.get(); }
     public float getPriceEach(){ return priceEach.get(); }
     public int getQuantity(){ return quantity.get(); }
     public float getProductTotal(){ return productTotal.get(); }
  
     public StringProperty productNameProperty() { return productName;}
     public FloatProperty priceEachProperty() { return priceEach;}
     public IntegerProperty quantityProperty() { return quantity;}
     public FloatProperty productTotalProperty() { return productTotal;}
  
     @Override
     public String toString(){
        return &quot; Product: &quot; + getProductName() +
                &quot;, Price: &quot; + getPriceEach() +
                &quot;, Quantity: &quot; + getQuantity() +
                &quot;, Total cost: &quot; + getProductTotal();
     }     
  }
  </code></pre>
  <p>I also have a Summary class with two properties that bind unidirectionally to the corresponding properties in the Products class. This is where the problem is.</p>
  <pre><code>import javafx.beans.property.*;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  
  public class Summary {
     private FloatProperty finalTotal;
     public ObservableList&lt;Item&gt; itemsSummary = FXCollections.observableArrayList(); 
  
     public Summary(){
        finalTotal=new SimpleFloatProperty(0);
     }
     public Item add()
     {
        Item newItem = new Item(); 
        itemsSummary.add(newItem);
        newItem.productTotalProperty().addListener((obs, oldAmount, newAmount) -&gt; {
              System.out.println(&quot;Item total changed from &quot;+oldAmount+&quot; to &quot;+newAmount);
              calculateTotal();
              System.out.println(&quot;Final total: &quot;+finalTotal);
           });
        return newItem;    
     } 
     
     public class Item{
        private final StringProperty productName;
        private  FloatProperty productTotal;
        
        public Item(){
           this.productName = new SimpleStringProperty(&quot;&quot;);
           this.productTotal =  new SimpleFloatProperty(-1);    
        }
        public void setProductName(String name) { productName.set(name); }
        public void setProductTotal(float total) { productTotal.set(total); }
        public String getProductName() { return productName.get(); }
        public float getProductTotal() { return productTotal.get(); }
        public StringProperty productNameProperty() { return productName;}
        public FloatProperty productTotalProperty() { return productTotal;}     
     }
     
     private void calculateTotal(){
        float runningTotal=0;
        for (Item i: itemsSummary )
           runningTotal+= i.getProductTotal();
        finalTotal.set(runningTotal);
     }
               
     @Override
     public String toString(){
        String output= &quot;&quot;;
        for(Item i: itemsSummary){
           String pn = i.getProductName();
           float  pt = i.getProductTotal();
           output = output +&quot;\n&quot;+ String.format(&quot;Product: %s,  Product cost: %.2f&quot;, pn, pt); 
        }
        return output+
                  &quot;\nFinal total: &quot; + finalTotal.getValue();
     }
  }
  </code></pre>
  <p>As you can see I have an inner class Item that contains the data (the name and the sub-totals). I've added a listener to the <code>newItem.productTotalProperty()</code>, but this only seems to work when the new Item is constructed: when a product's field is changed, its instance's total is updated, but the binding to the Summary object stops working, so none of its fields are changed.</p>
  <p>Here is the test driver code:</p>
  <pre><code>import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  
  public class BindingsPrototypeTestDriver {
     public static void main(String[] args)
     {
        Product A = new Product(&quot;Pencil&quot;, 1.50f, 300);
        Product B = new Product(&quot;Eraser&quot;, 0.50f, 200);
        Product C = new Product(&quot;Paper&quot;, 4.95f, 100);
        ObservableList&lt;Product&gt; products = FXCollections.observableArrayList(); 
        products.add(A);
        products.add(B);
        products.add(C);
        Summary summary = new Summary();
        for(Product p: products)
        {
           Summary.Item summaryItem = summary.add();
           summaryItem.productNameProperty().bind(p.productNameProperty());
           summaryItem.productTotalProperty().bind(p.productTotalProperty());
        }
        
               for(Product p: products){ System.out.println(p.toString()); }
               System.out.println(summary.toString());
        C.setQuantity(200);
              for(Product p: products){ System.out.println(p.toString()); }
              System.out.println(summary.toString());
     }   
  }
  </code></pre>
  <p>and here is the output:</p>
  <pre><code>run:
  Item total changed from -1.0 to 450.0
  Final total: FloatProperty [value: 450.0]
  Item total changed from -1.0 to 100.0
  Final total: FloatProperty [value: 550.0]
  Item total changed from -1.0 to 494.99997
  Final total: FloatProperty [value: 1045.0]
  Product: Pencil, Price: 1.50, Quantity: 300, Total cost:  450.00
  Product: Eraser, Price: 0.50, Quantity: 200, Total cost:  100.00
  Product: Paper, Price: 4.95, Quantity: 100, Total cost:  495.00
  
  Product: Pencil,  Product cost: 450.00
  Product: Eraser,  Product cost: 100.00
  Product: Paper,  Product cost: 495.00
  Final total: 1045.0
  Product: Pencil, Price: 1.50, Quantity: 300, Total cost:  450.00
  Product: Eraser, Price: 0.50, Quantity: 200, Total cost:  100.00
  Product: Paper, Price: 4.95, Quantity: 200, Total cost:  990.00
  
  Product: Pencil,  Product cost: 450.00
  Product: Eraser,  Product cost: 100.00
  Product: Paper,  Product cost: 495.00
  Final total: 1045.0
  </code></pre>
  <p>As you can see, when the &quot;Paper&quot; instance's quantity is changed to 200, everything updates correctly in the Product instance, but not in the Summary...</p>
  <p>What am I doing wrong?</p>