gpt4 book ai didi

JavaFX:从 DoubleProperty 的 ObservableSet 获取值的运行总计

转载 作者:行者123 更新时间:2023-12-02 01:57:02 25 4
gpt4 key购买 nike

我有一个ObservableSet<DoubleProperty> itemSet 包含 DoubleProperty prop1 对于任意数量的 Item 实例.

我想创建另一个DoubleProperty 总计将反射(reflect)所有 DoubleProperty 的最新总计位于 itemSet 中。

每个 DoubleProperty 的 double 值集合中可以独立改变。 值需要反射(reflect)这些变化。

这是Item类:

class Item {
DoubleProperty prop1;
DoubleProperty prop2;

public Item() {
this.prop1 = new SimpleDoubleProperty(1.0);
this.prop2 = new SimpleDoubleProperty(2.0);

itemSet.add(this.prop1);
}
}

这是一种全局变量类...

class ItemValue {
private ItemValue itemValue = null;

ObservableSet<DoubleProperty> itemSet = FXCollections.observableSet();
DoubleProperty total;

private ItemValue() {
this.total = new SimpleDoubleProperty(0.0);

// create several Item's here...

itemSet.addListener((InvalidationListener) observable -> {
/*
Something which binds the total
I figure it will need to go here so that if new items get added the total will reflect that?
*/
});
}

public ItemValue get() {
if (itemValue == null) itemValue = new ItemValue();
return itemValue;
}

最佳答案

据我所知,没有内置的方法可以简单地做到这一点。不过,有几种方法可以做到这一点。最(?)有效但更复杂的方法是监听 ObservableSet 的添加/删除,观察任何当前的 DoubleProperty 元素,并自己修改 total 属性。

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener;

public class SomeClass {

private final ReadOnlyDoubleWrapper total = new ReadOnlyDoubleWrapper(this, "total");
private void setTotal(double total) { this.total.set(total); }
public final double getTotal() { return total.get(); }
public final ReadOnlyDoubleProperty totalProperty() { return total.getReadOnlyProperty(); }

private final ObservableSet<DoubleProperty> propertySet = FXCollections.observableSet();
private final ChangeListener<Number> elementListener = this::elementValueChanged;
private final WeakChangeListener<Number> weakElementListener =
new WeakChangeListener<>(elementListener);

public SomeClass() {
propertySet.addListener(this::propertySetChanged);
}

private void propertySetChanged(SetChangeListener.Change<? extends DoubleProperty> change) {
if (change.wasRemoved()) {
change.getElementRemoved().removeListener(weakElementListener);
setTotal(getTotal() - change.getElementRemoved().get());
}
if (change.wasAdded()) {
change.getElementAdded().addListener(weakElementListener);
setTotal(getTotal() + change.getElementAdded().get());
}
}

private void elementValueChanged(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
setTotal(getTotal() - oldValue.doubleValue() + newValue.doubleValue());
}

}

这里的 SetChangeListener ,其值是对 propertySetChanged 的方法引用,监视 ObservableSet 的任何更改。当添加 DoubleProperty 时,它​​会将所述属性的值添加到当前总计中。当 DoubleProperty删除时,它会从当前总计中减去该属性的值。当在 ChangeListener 中添加或删除 DoubleProperty 时,此监听器还会分别向 ObservableSet 添加或删除 ChangeListener

elementValueChanged 的值是对 total 的方法引用,当任何 DoubleProperty 的值发生更改时,它会更新 WeakChangeListener 属性。它通过首先减去旧值,然后将新值添加到当前总计中来实现此目的。它实际上是 ChangeListener ,它包装了添加或删除的原始 ChangeListener 。这有助于避免潜在的内存泄漏。请记住在使用 WeakChangeListener 时保持对原始 ChangeListener 的强引用,否则原始 ObservableSet 可能会过早被垃圾回收。

第二个选项是每次 total 失效时重建绑定(bind),然后将 InvalidationListener 属性绑定(bind)到所述绑定(bind)。

import javafx.beans.Observable;
import javafx.beans.binding.DoubleExpression;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;

public class SomeClass {

private final ReadOnlyDoubleWrapper total = new ReadOnlyDoubleWrapper(this, "total");
private void setTotal(double total) { this.total.set(total); }
public final double getTotal() { return total.get(); }
public final ReadOnlyDoubleProperty totalProperty() { return total.getReadOnlyProperty(); }

private final ObservableSet<DoubleProperty> propertySet = FXCollections.observableSet();

public SomeClass() {
propertySet.addListener(this::propertySetInvalidated);
}

private void propertySetInvalidated(Observable observable) {
if (propertySet.isEmpty()) {
total.unbind();
setTotal(0.0);
} else if (propertySet.size() == 1) {
total.bind(propertySet.iterator().next());
} else {
DoubleExpression sum = null;
for (DoubleProperty property : propertySet) {
sum = (sum != null) ? sum.add(property) : property;
}
total.bind(sum);
}
}

}

在本例中,我们将 ObservableSet 添加到 ObservableSet 中。每当向 ObservableSet 添加或删除元素时,都会调用此监听器。当发生这种情况时,将会发生以下 3 件事之一:

  1. 如果 total 现在为空,请取消绑定(bind) ObservableSet 属性并将其设置为零。
    • 这是处理无元素的特殊情况
  2. 如果 total 现在仅包含单个元素,只需将 total 属性绑定(bind)到该元素即可。
    • 处理单个元素的另一个特殊情况。它阻止我们创建不必要的对象并执行不必要的计算,如果我们跳到第三个分支就会发生这种情况。
  3. 否则,创建一个计算总和的大绑定(bind),然后将 DoubleExpression.add(ObservableNumberValue) 绑定(bind)到该绑定(bind)。
    • 该分支使用 DoubleBinding 。每当两个可观察量之一发生变化时,该方法调用生成的 DoubleExpression 就会更新。这被简化为单个 total,然后我们将 ObservableSet 属性绑定(bind)到它。

第二个选项效率较低,因为它每次都需要迭代整个 DoubleBinding。它还可能导致创建大量 ojit_code 对象。但是,您可能会发现它更易于编码/理解,并且性能影响对于您的应用程序来说可能不够显着。

关于JavaFX:从 DoubleProperty 的 ObservableSet 获取值的运行总计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52175194/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com