如何处理 Property<T>、更改监听器和属性的初始化?

Posted

技术标签:

【中文标题】如何处理 Property<T>、更改监听器和属性的初始化?【英文标题】:How to deal with Property<T>, a change listener and initialization of the property? 【发布时间】:2014-10-05 05:39:42 【问题描述】:

我正在使用 JavaFX 的 Property&lt;T&gt; 类,我对结果非常满意,缩小了示例代码:

public CircularListCursor<E> 
    private final Property<E> elementProperty;

    public CircularListCursor() 
        this.elementProperty = new SimpleObjectProperty(/*some value*/);
    

    //various methods that call elementProperty.setValue(/*some value*/);

用法:

private final CircularListCursor<SelectionData> selectionDataCursor;

...

selectionDataCursor.elementProperty().addListener((observableValue, oldValue, newValue) -> 
    oldValue.getLabel().setStyle("-fx-text-fill: black");
    newValue.getLabel().setStyle("-fx-text-fill: red");
);

现在这几乎完美地工作了,但它不会触发对象的构造。它以这种方式工作是合乎逻辑的,因为在构造期间该属性尚未绑定,因此也无法触发任何更改事件。

但我确实希望在构造过程中收到初始值的通知以允许编写干净的代码,有没有办法做到这一点?

【问题讨论】:

所以您在构造时注册了一个内部ChangeListener(= 在CircularListCursor 的构造函数中)? @isnot2bad 不,ChangeListener 正在外面注册。 所以您希望它在注册时(调用addListener 时)获得某种初始触发器? @isnot2bad 正确,我的想法是这样的 好的,知道了。没有开箱即用的支持。我们总是直接使用私有方法作为监听器(Java 8 方法引用),因此我们可以在构造结束时调用它们一次进行初始化。 【参考方案1】:

使用EasyBind,您可以

    elementProperty中选择嵌套的styleProperty。 将嵌套的styleProperty 绑定到某个可观察的字符串(在您的情况下,为红色文本填充的常量字符串)。 为bind 方法提供一个额外的字符串参数,用于在元素更改时重置旧元素的样式属性。

代码如下:

ObservableValue<String> constRed = new SimpleStringProperty("-fx-text-fill: red");
EasyBind.monadic(selectionDataCursor.elementProperty())
        .selectProperty(e -> e.getLabel().styleProperty())
        .bind(constRed, "-fx-text-fill: black");

请注意,您无需注册任何侦听器——一个绑定即可完成所有工作。绑定更具声明性,而侦听器则更具命令性(副作用)。

【讨论】:

【参考方案2】:

JavaFX 中没有直接的解决方案。

尽管如此,您可以通过将侦听器代码移动到私有事件处理程序方法中来使事情变得更容易/更清晰。然后可以在构造结束时调用此方法一次以初始化您的对象状态。感谢 Java 8 lambda 表达式,您可以直接将事件处理程序方法的方法引用用作侦听器:

// register event handler method    
selectionDataCursor.elementProperty().addListener(this::onElementChanged);

// call listener once for initialization:
onElementChanged(selectionDataCursor.elementProperty(), null, selectionDataCursor.getElement());

...

// event handler method
private void onElementChanged(ObservableValue<? extends E> observableValue, E oldValue, E newValue) 
    if (oldValue != null) oldValue.getLabel().setStyle("-fx-text-fill: black");
    if (newValue != null) newValue.getLabel().setStyle("-fx-text-fill: red");


旁注:通过方法引用构建的侦听器无法再删除。更具体地说,以下代码不会删除监听器,因为this::onElementChanged 每次都会创建一个新的监听器,而不是已经注册的监听器:

selectionDataCursor.elementProperty().removeListener(this::onElementChanged);

【讨论】:

+1 用于提及方法引用的侦听器删除。但是,如果声明了侦听器(即使作为方法引用),那么它们可以被删除,例如:private ChangeListener exampleListener = this::onElementChanged;

以上是关于如何处理 Property<T>、更改监听器和属性的初始化?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 UserControl 中属性的可见性?

C ++自定义控制台类 - 如何处理“<

如何处理泛型函数中的空 Guid?

出现“需要提供管理员权限来更改这些属性”时,该如何处理?怎样才能获得管理员权限呢?我的系统是win7

如何处理指向通用接口的指针的 JPA 注释

Envers 如何处理架构更改?