如何处理相关的FX属性? [英] How to handle correlated FX properties?

查看:74
本文介绍了如何处理相关的FX属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

属性-ol'风格的Bean属性与闪烁的fx属性相同-如果它们彼此正交,则效果最佳.如果它们之间存在某种联系,它们就会带来问题-还是两种类型.在讨厌的真实世界中,发生这种情况的频率可能比我们希望的高.

作为一个例子,使用两个选定的selectedIndex/selectedItem:如果索引包含列表中的项,则索引指向该项的位置;如果不包含索引,则指向项的负数.更新一个也需要更新另一个.

对于Java Bean,解决方案是简单,因为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的地方还是在客户端?不知何故推迟了大火?绝妙的Platform.runLater()散布在所有应用程序代码中吗?陷入困境..

解决方案

根据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();
}

当子类化最终确定其相关属性的核心类时,一个选择可能会变得肮脏:通过反射将其替换.一个例子是

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

Properties - ol' style bean properties just the same as blinky fx properties - work best if they are orthogonal to each other. They pose problems - again, both types - if they are somehow correlated. Which might happen in nasty Real World more often than we like.

As an example take the twosome selectedIndex/selectedItem: the index points to the position of the item in a list if it is contained, or is negative if not. Updating one requires to update the other as well.

For java beans, the solution is straightforward because the bean itself has full control about when to fire the changes. And for fx beans?

A base pattern used in 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);
}

The properties fire at the time of calling their setters, the bean has no control. As internal state is unstable between those calls, listeners to the first must not access the second on receiving the notification .. as they can’t know which is the first to fire, they cannot rely on the bean being stable, ever.

What to do now, either on owning bean or client side? Somehow defer the fire? The ol' trick Platform.runLater() scattered all over application code? Stumped ..

解决方案

As suggested by James_D, ReactFX' InhiBeans come to the rescue.

When coding a bean from scratch, use the properties provided by that package - they extend core classes, have the same names so its as simple as exchanging the imports. Then guard modifying methods like:

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

When subclassing core classes that finalized their correlated properties an option might be to go dirty: replace them via reflection. An example is AbstractSelectionModelBase which currently is the base MultipleSelectionModel in my experiments

// 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);
}

Would be cool to have (and use it!) such a feature in core.

这篇关于如何处理相关的FX属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆