当前位置: 首页 > 知识库问答 >
问题:

具有绑定的javafx跨类触发器计算

刘承运
2023-03-14

我有点卡住了,也许有人能帮上忙。我想有一个“总额”计算每当某些字段改变。

我在excel中制作了一个原型来说明:

因此,每当价格或数量发生变化时,总成本就会重新计算,汇总也应该更新,包括“最终总额”。我已经使用了绑定,但它们不起作用,除非是在首次创建汇总项时,然后finalTotal字段不会重新计算。

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("Product Name");
      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 " Product: " + getProductName() +
              ", Price: " + getPriceEach() +
              ", Quantity: " + getQuantity() +
              ", Total cost: " + getProductTotal();
   }     
}
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Summary {
   private FloatProperty finalTotal;
   public ObservableList<Item> 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) -> {
            System.out.println("Item total changed from "+oldAmount+" to "+newAmount);
            calculateTotal();
            System.out.println("Final total: "+finalTotal);
         });
      return newItem;    
   } 
   
   public class Item{
      private final StringProperty productName;
      private  FloatProperty productTotal;
      
      public Item(){
         this.productName = new SimpleStringProperty("");
         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= "";
      for(Item i: itemsSummary){
         String pn = i.getProductName();
         float  pt = i.getProductTotal();
         output = output +"\n"+ String.format("Product: %s,  Product cost: %.2f", pn, pt); 
      }
      return output+
                "\nFinal total: " + finalTotal.getValue();
   }
}
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class BindingsPrototypeTestDriver {
   public static void main(String[] args)
   {
      Product A = new Product("Pencil", 1.50f, 300);
      Product B = new Product("Eraser", 0.50f, 200);
      Product C = new Product("Paper", 4.95f, 100);
      ObservableList<Product> 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());
   }   
}
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

共有1个答案

胡俊贤
2023-03-14

您的代码有一些问题。

您遇到的问题是,ProductTotal使用的属性不更新,而是在每次更新值时用新的property对象替换。您的产品类的用户不可能知道这一点。实际上,用户希望属性获取器总是返回相同的实例(您也希望如此)。

为了简单起见,不创建新属性,而是为旧属性赋一个新值,或者只使用bindings类:

public class Product {
   private final StringProperty productName;
   private final FloatProperty priceEach;
   private final IntegerProperty quantity;
   private final FloatProperty productTotal;

   public Product(){
       this("Product Name", 0, 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 = new SimpleFloatProperty();
      this.productTotal.bind(Bindings.multiply(this.quantity, this.priceEach));
   }

   public void setPriceEach(float price){
      priceEach.set(price);
   }

   ...
    null
    null
public class Summary {

    private final FloatProperty finalTotal;
    public final ObservableList<Product> itemsSummary;

    private final ChangeListener<Number> itemTotalChangeListener = (observable, oldValue, newValue) -> {
        calculateTotal();
    };

    public Summary() {
        finalTotal = new SimpleFloatProperty(0);
        itemsSummary = FXCollections.observableArrayList();
        itemsSummary.addListener((ListChangeListener.Change<? extends Product> c) -> {
            boolean modified = false;
            while (c.next()) {
                if (c.wasRemoved()) {
                    modified = true;
                    for (Product p : c.getRemoved()) {
                        p.productTotalProperty().removeListener(itemTotalChangeListener);
                    }
                }
                if (c.wasAdded()) {
                    modified = true;
                    for (Product p : c.getAddedSubList()) {
                        p.productTotalProperty().addListener(itemTotalChangeListener);
                    }
                }
            }

            if (modified) {
                calculateTotal();
            }
        });
    }

    ...
    Product A = new Product("Pencil", 1.50f, 300);
    Product B = new Product("Eraser", 0.50f, 200);
    Product C = new Product("Paper", 4.95f, 100);

    // no need for a observable list here
    Product[] products = new Product[]{A, B, C};

    Summary summary = new Summary();
    summary.itemsSummary.setAll(products);

    for (Product p : products) {
        System.out.println(p.toString());
    }
    ...
 类似资料:
  • 我在Azure上有一个函数,包含以下function.json文件: 除非我错了,否则这个函数应该每天运行一次,在凌晨3点? 这是函数的签名: 我到底做错了什么?当我手动触发(在门户中单击“运行”)时,该功能工作正常,但它在今天凌晨3点没有运行,昨天也没有运行。 编辑:所以,正如建议的那样,我已经将计划更改为付费计划,并且我选择了一个动态计划。日志仍然没有说明功能在今天早上3点被激活。

  • 我想在我的应用程序中添加一个时钟,它告诉你已经做了多长时间的任务。为了简化它,我包含了一个计数器,它在新线程中每秒递增一次,并用计数器号更新标签“Set Timer”。为此,我在我的.fxml文件中有一个标签fx:id=“settimer”,并将其导入到我的类中。 我试过很多方法来解决我的问题,但我还没有找到正确的方法。我对我想做什么的想法应该很清楚,如果有人能帮助我,我会很高兴的。我的问题是更新

  • 我正在运行Visual Studio 2017预览并在本地运行函数代码,我正在使用开箱即用的Azure函数项目模板。我试图让一个由定时器触发的Azure函数使用输出绑定向服务总线队列发送消息,但WebJob SDK似乎无法将输出绑定到字符串类型。 结合 定时器功能 错误消息 TimerTriggerCSharp: Microsoft.Azure.WebJobs.Host: Error indexi

  • 我已经审阅了Microsoft提供的关于触发器的文档。[https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob-trigger?tabs=python][1] 事实上,在Azure函数中使用参数允许我们检索blob和一些属性(),我们还可以使用函数读取字节,但是我们如何将字节转换为

  • 关于在物联网场景中使用EventHub的Azure功能,我有几个问题。 EventHub有分区。通常来自特定设备的消息会发送到同一个分区。Azure Function的实例如何分布在EventHub分区中?它是基于性能的吗?如果Azure Function的一个实例设法处理来自所有分区的事件,那么这就足够了,否则每个EventHub分区可能会有一个Azure Function的实例? 读取偏移量呢

  • 我知道Java和C#,但属性绑定我只知道C#MVVM。我试图理解JavaFX中的属性绑定,使用属性值的自定义getter和setter(就像在C#中一样)。 我创建了以下类: 我的印象是,如果我遵循推荐的JavaBean/JavaFX命名约定,那么绑定系统将足够聪明地使用反射(?)并为该属性使用自定义getter/setter。但是我的视图模型getter/setter从来没有使用过。 在C#中,