【问题标题】:How to handle correlated FX properties?如何处理相关的外汇属性?
【发布时间】:2014-11-28 10:32:49
【问题描述】:

属性 - ol' 样式 bean 属性与闪烁的 fx 属性相同 - 如果它们相互正交,则效果最佳。如果它们以某种方式相关,它们会带来问题 - 再次,两种类型。这可能比我们喜欢的更频繁地发生在令人讨厌的现实世界中。

以两个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);
}

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

现在要做什么,无论是拥有 bean 还是客户端?以某种方式推迟火灾?旧把戏 Platform.runLater() 散布在应用程序代码中?难倒..

【问题讨论】:

  • 无论如何,这种形式的SelectionModel 是个坏主意,因为它在下面强制使用基于整数的模型。基本上这应该只是一个属性。例如:我的 JFXtras CalendarPicker 很想实现 SelectionModel,但由于它没有整数的概念,所以不能。也就是说,相关属性的基本问题并没有用那句话解决。也许他们应该有一个“推迟事件”的方法。
  • @tbeernot 不要让我开始使用 SelectionModel ;-) 感谢您的评论,一直在考虑类似的思路(但无济于事)
  • Tomas Mikula 将此作为其ReactFX 框架的一部分。
  • @James_D 感谢您的参考!尚未查看代码,但在描述中偶然发现“无效侦听器按照注册的顺序执行” - 对我来说听起来像是假设/实现细节,还是在某处指定了通知序列?

标签: java properties javafx-8


【解决方案1】:

正如 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);
}

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

【讨论】:

  • 我没有看到改进的方法(其他人可能......)。在使用选择模型时,我基本上避免与selectedIndexPropertyselectedItemProperty 进行交互。具体来说,如果我只需要该项目(通常情况下),我使用selectedItemProperty。如果我需要索引,我使用selectedIndexProperty,然后如果我需要两者(即T item = listView.getItems().get(listView.getSelectionModel().getSelectedIndex());),请返回原始列表。在indexPropertyitemProperty 的单元实现中也会出现类似的问题。
  • @James_D 是的,selectionModel 仅作为示例。也许唯一的出路(没有 reactfx 的核心支持)是知道哪些属性可能是相关的(它并不总是像这里那样明显)并且总是针对最坏的情况进行防御性编码。
  • 这基本上是推迟的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 2015-02-25
  • 2018-02-21
  • 1970-01-01
相关资源
最近更新 更多