如何处理相关的FX属性?

时间:2014-11-28 10:32:50

标签: java properties javafx-8

属性 - ol'样式bean属性与blinky fx属性相同 - 如果它们彼此正交,则效果最佳。如果它们以某种方式相互关联,它们会再次出现问题 - 两种类型。这可能发生在令人讨厌的真实世界中,而不是我们喜欢的。

作为示例,取twosome selectedIndex / selectedItem:索引指向列表中项目的位置(如果包含),否则为否定。更新一个也需要更新另一个。

对于java bean,解决方案是straightforward,因为bean本身可以完全控制何时触发更改。对于fx bean?

SelectionModel

中使用的基本模式
Property<T> theRealItemProperty = new SimpleObjectProperty<>();
ReadOnlyProperty<T> readOnlyItemProperty = new ReadOnlyObjectProperty(theRealItemProperty);
/**
 * Public access is read-only
 */
public final ReadOnlyProperty<T> itemProperty() {
    return readOnlyItemProperty;
}
/**
 *  Setting allowed for subclasses only (and mis-behaving package neighbors ;-)
 */
protected final void setItem(T item) {
    theRealItemProperty.set(item);
}
/**
 * Special setting api for general public
 */
public void select(T item) {
   setIndex(indexOf(item));
   setItem(item);
}

在调用setter时,属性会触发,bean无法控制。由于内部状态在这些调用之间是不稳定的,因此第一个侦听器在接收通知时不能访问第二个...因为他们不知道哪个是第一个触发,所以他们不能依赖于bean是稳定的。

现在该怎么做,无论是拥有bean还是客户端?以某种方式推迟火灾? ol&#39;技巧Platform.runLater()分散了所有应用程序代码?难倒..

1 个答案:

答案 0 :(得分:2)

正如James_D所建议的,ReactFX' InhiBeans来救援。

从头开始编写bean时,使用该包提供的属性 - 它们扩展核心类,具有相同的名称,因此它与交换导入一样简单。然后保护修改方法,如:

public void select(T item) {
   Guard guard = Guard.multi(theRealItemProperty.guard(), 
       theRealIndexProperty.guard());
   setIndex(indexOf(item));
   setItem(item);
   guard.close();
}

当子类化最终确定其相关属性的核心类时,一个选项可能是变脏:通过反射替换它们。一个例子是AbstractSelectionModelBase,它目前是我实验中的基础MultipleSelectionModel

// going dirty: replace super's selectedItem/Index property 
// with guarded cousins 
itemReplacement = new ReadOnlyObjectWrapper<>(this, "selectedItem");
replaceField("selectedItem", itemReplacement);
indexReplacement = new ReadOnlyIntegerWrapper(this, "selectedIndex", -1);
replaceField("selectedIndex", indexReplacement);

// usage in methods that update single selection state
protected void syncSingleSelectionState(int selectedIndex) {
    Guard guard = Guard.multi(itemReplacement.guard(), indexReplacement.guard());
    setSelectedIndex(selectedIndex);
    if (selectedIndex > -1) {
        setSelectedItem(getModelItem(selectedIndex));
    } else {
        // PENDING JW: do better? can be uncontained item
        setSelectedItem(null);
    } 
    guard.close();
    focus(selectedIndex);
}

在核心中拥有(并使用它!)这样的功能会很酷。