javafx:绑定(bind)未按预期工作

标签 java javafx

我想拥有一个属性 total这是通过将两个属性相乘得到的,即 currentPricevolumeHeld , 其中currentPrice实际上是通过每 10 秒下载 google finance 股票价格获得的。它每 10 秒自动更新一次。

现在 getCurrentPrice()0 初始化,如代码所示。 10 秒后,它获得了一个新值,一切正常。

但是在下面的绑定(bind)方法中,total currentPrice 时不会自动更新属性(property)发生了变化。

totalBinding = Bindings.createDoubleBinding(() -> {
        System.out.println("current price: " + getCurrentPrice() + "vol held: " + getVolumeHeld());
        return getCurrentPrice() * getVolumeHeld();
    });

   total.bind(totalBinding);

问题:我发现在 createDoubleBinding 中上面的语句,getCurrentPrice()值为 0(如上所述),当其值更改时,更改不会在 total 中传播属性(property)。我的意思是 total属性无法从 getCurrentPrice() 中获取新值即使当前价格发生变化。

所以问题是双重的,但我猜下面两个问题的解决方案即使不完全相同也会相似:

  1. 如何解决上述问题?

  2. 稍后,我将绑定(bind)此 total属性(property)到另一个属性(property)计算出总数total所有人的属性(property)Trade对象)。这失败得很惨,它总是等于 0。这个方法是在不同的类中编写的,即不在 Trade 类中。

更新:

代码如下:

class SummaryofTrade{
    ...     
    sumOfTotals = new ReadOnlyDoubleWrapper();
    sumOfTotalsBinding = Bindings.createDoubleBinding(() -> {
        double sum = 0;
        for(Trade t : this.observableListOfTrades){
            sum += t.getTotal();
        }
        return sum;         
    }, total);     // I cannot put "total" as a second parameter, as it is a property that resides in the Trade class , not this class.
    sumOfTotals.bind(sumOfTotalsBinding);
    ...
}

错误日志信息:

Caused by: java.lang.Error: Unresolved compilation problem: 
    total cannot be resolved to a variable

请注意 sumOfTotalsBindingsumOfTotals住在另一个类(class)。

下面的贸易对象代码:

class Trade{
      ...
      private final ReadOnlyDoubleWrapper total;
      private final ReadOnlyDoubleWrapper currentPrice;
      private DoubleProperty volumeHeld;
      public DoubleBinding totalBinding;



      private final ScheduledService<Number> priceService = new ScheduledService<Number>() {
        @Override
        public Task<Number> createTask(){
            return new Task<Number>() {
                @Override
                public Number call() throws InterruptedException, IOException {
                    return getCurrentPriceFromGoogle();
                }
            };
        }
       };

    public Trade(){
       ...
       priceService.setPeriod(Duration.seconds(10));
        priceService.setOnFailed(e -> priceService.getException().printStackTrace());
        this.currentPrice   = new ReadOnlyDoubleWrapper(0);
        this.currentPrice.bind(priceService.lastValueProperty());
        startMonitoring();
        this.total          = new ReadOnlyDoubleWrapper();
        DoubleBinding totalBinding = Bindings.createDoubleBinding(() ->
          getCurrentPrice() * getVolumeHeld(),
          currentPriceProperty(), volumeHeldProperty());                
       total.bind(totalBinding);
     }


        // volume held
    public double getVolumeHeld(){
        return this.volumeHeld.get();
    }

    public DoubleProperty volumeHeldProperty(){
        return this.volumeHeld;
    }

    public void setVolumeHeld(double volumeHeld){
        this.volumeHeld.set(volumeHeld);
    }

        // multi-threading
    public final void startMonitoring() {
         priceService.restart();
    }

    public final void stopMonitoring() {
        priceService.cancel();
    }

        public ReadOnlyDoubleProperty currentPriceProperty(){
         return this.currentPrice.getReadOnlyProperty();
    }

    public final double getCurrentPrice(){
        return currentPriceProperty().get();
    }

        // total
    public final Double getTotal(){
        return totalProperty().getValue();
    }

    public ReadOnlyDoubleProperty totalProperty(){
        return this.total;
    }
}

2015 年 9 月 15 日更新:

我试图在这里以合乎逻辑的方式阐述我的问题。如果这没有意义,请告诉我。谢谢。

首先,在 Trade class上面(请注意上面的代码已经更新并且指定了属性依赖),每个 Trade 对象包含一个 total属性(property),这是currentPrice的产品和 VolumeHeld .如果用户手动编辑当前价格和持有量的值。 total属性将自动更新。

现在,我有一个 Trade 对象的 ObservableList,每个对象都有一个 total属性(property)。我的目标是总结 total可观察列表中每个 Trade 对象的属性,并将总和绑定(bind)到名为 sumOfTotals 的变量.这是在一个名为 SummaryOfTrade 的类中完成的.每当 total Observable 列表中任何一项交易的属性发生变化时,sumOfTotals属性也应该自动更改。

class SummaryofTrade{
    ...     
    // within constructor, we have
    sumOfTotals = new ReadOnlyDoubleWrapper();
    sumOfTotalsBinding = Bindings.createDoubleBinding(() -> {
        double sum = 0;
        for(Trade t : this.observableListOfTrades){
            sum += t.getTotal();
        }
        return sum;         
    }, totalProperty());    
    sumOfTotals.bind(sumOfTotalsBinding);
    ...
}

这就是问题所在。Eclipse 说它无法识别 Trade 对象的属性 totalProperty .错误信息如下所示。

错误日志信息:

Caused by: java.lang.Error: Unresolved compilation problem: 
    The method totalProperty() is undefined for the type SummaryOfTrade

我已经指定了属性依赖关系,但 Eclipse 抛出错误。我该如何解决?

最佳答案

由于当前价格和持有量都是属性,您可以直接绑定(bind)它们:

total.bind(currentPriceProperty().multiply(volumeHeldProperty()));

如果您绝对需要使用自定义双重绑定(bind),您首先需要提供依赖项,以便在依赖项根据 documentation 失效后执行计算。 :

DoubleBinding totalBinding = new DoubleBinding() {

     {
         super.bind(currentPrice, volumeHeld);
     }

     @Override
     protected double computeValue() {
         return currentPrice.get() * volumeHeld.get();
     }
 };

Bindings 提供的以下辅助函数也应该有效:

DoubleBinding totalBinding = Bindings.createDoubleBinding(() ->
        currentPrice.get() * volumeHeld.get(),
        currentPrice, volumeHeld);

关于javafx:绑定(bind)未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32536096/

相关文章:

java - 如何从主应用程序的 init() 方法调用 JavaFX 应用程序预加载器实例中的方法

java - 为什么用Java开发的应用程序顶部有一个透明但很小的面板?

java - 在 Java 中,如何将所有 future 的 System.out.println 输出重定向到我刚刚打开的新终端窗口?

java - 在 Wildfly 10 上使用 ActiveMQ Artemis 的 Websockets/STOMP 无法正常工作

java - 如何从 java 代码获取 Maven 项目 BaseDir()

JavaFx 的 Javascript 函数监听器功能

在 JavaFX 应用程序线程以外的线程上进行 ImageIO 调用的 JavaFX 应用程序在 Mac OS X 上挂起

Java邮件|消息异常

java - 如何修复折线图十字准线的位置

java - 在 javafx 中的 gridpane 中的 Pane 上放置标签