【问题标题】:Reject changes out of bound range on DoubleProperty拒绝 DoubleProperty 上超出范围的更改
【发布时间】:2016-09-19 18:35:00
【问题描述】:

我最近试图将我的双重属性的范围限制为(0.0 - 1.0)。超出此范围的更改不应产生任何影响,或引发错误。

目前我有两种方法:

  • 只读,只允许在访问器上更改:

    private ReadOnlyDoubleWrapper numProperty = new ReadOnlyDoubleWrapper(0);
    
    public final double getNum() {
        return numProperty().get();
    }
    
    public final void setNum(double num) {
        if(num < 0)
            num = 0;
        if(num > 1)
            num = 1;
        numProperty.set(num);
    }
    
    public ReadOnlyDoubleProperty numProperty() {
        return numProperty.getReadOnlyProperty();
    }
    
  • 设置监听器重置值:

    private DoubleProperty numProperty = new SimpleDoubleProperty(0);
    numProperty.addListener(new BoundRangeListener(numProperty, 0.0, 1.0));
    
    
    class BoundRangeListener implements ChangeListener<Number> {
    
        Property<Number> prop;
        double min, max;
    
        BoundRangeListener(Property<? extends Number> prop, double min, double max) {
            this.prop = prop;
            this.min = min;
            this.max = max;
        }
    
        public void changed(ObservableValue<? extends Number> o,
                                             Number oldValue, Number newValue) {
            if(newValue.doubleValue() < min)
                prop.set(min);
            if(newValue.doubleValue() > max)
                prop.set(max);
    
            // Optional: throw exception
        }
    
    }
    

不过,我对这两种解决方案都不满意。第一个不允许我的用户绑定属性;不是我想要的,没有充分的理由。第二个将向其他侦听器触发 2 个事件;不好。

所以我的问题是:是否有任何开箱即用的方法来拒绝更改,或将 number 属性绑定到一个范围?

【问题讨论】:

  • 我将使用ReadOnlyDoubleWrapper 代替DoubleProperty 重构第一个解决方案,numProperty() 方法返回numProperty.getReadOnlyProperty()。您还可以考虑继承 SimpleDoubleProperty 并覆盖 set(...)setValue(...) 方法。 (虽然有点难以真正回答这个问题,除非你说出为什么你对现有的解决方案不满意。)
  • 压倒一切...没想到这个... +1。将其发布为答案。
  • 已编辑,为什么我不舒服。

标签: java javafx properties


【解决方案1】:

考虑继承 SimpleDoubleProperty 并覆盖 setsetValue 方法:

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class ClampedDoublePropertyTest {

    private DoubleProperty numProperty = new SimpleDoubleProperty(0) {

        @Override
        public void set(double value) {

            System.out.println("set("+value+")");
            if (value < 0) {
                value = 0 ;
            }
            if (value > 1) {
                value = 1 ;
            }
            super.set(value);
        }

        @Override
        public void setValue(Number value) {
            System.out.println("setValue("+value+")");
            if (value == null) {
                // depending on requirements, throw exception, set to default value, etc.
            } else {
                if (value.doubleValue() < 0) {
                    value = new Double(0);
                }
                if (value.doubleValue() > 1) {
                    value = new Double(1);
                }
                super.setValue(value);
            }
        }

    };

    public DoubleProperty numProperty() {
        return numProperty;
    }

    public final double getNum() {
        return numProperty().get();
    }

    public final void setNum(double num) {
        numProperty().set(num);
    }

    public static void main(String[] args) {
        ClampedDoublePropertyTest test = new ClampedDoublePropertyTest();
        test.numProperty().addListener((obs, oldValue, newValue) -> System.out.println(oldValue +" -> "+newValue));

        DoubleProperty value = new SimpleDoubleProperty();
        test.numProperty().bind(value);
        value.set(0.5);
        value.set(2);
        value.set(-5);
    }
}

这将允许客户端代码以通常的方式绑定属性:

myInstance.numProperty().bind(...);

虽然注意这会违反通常的绑定契约,就好像它绑定的可观察值超出范围一样,这两个值将不相等。

顺便说一句,FWIW Oracle recommend(幻灯片 29)是侦听器方法,尽管我同意您的观点,我不喜欢它(特别是因为它允许观察者观察到“无效值”)。

【讨论】:

  • 或者我可以抛出异常而不是违反约束性合同。 (就像它会,如果你试图绑定一个绑定的属性)。
  • 是的,这也是一种选择。但是,我认为这不会否决对其绑定的属性的更改,因此您最终仍会导致属性不同步...
  • 不,程序崩溃了。
  • bindBidirectional() 怎么样,我也必须重写它吗?
  • 是否需要重写绑定方法?我认为覆盖这两个 set 方法就足够了。甚至可能只有 setValue 方法。
【解决方案2】:

我已经实现了LimitedComparableProperty。也许你觉得它很有用。

double minValue = 0;
double maxValue = 1;
LimitedComparableProperty<Double> numProperty = new LimitedComparableProperty<>(this, "numProperty", 0, minValue , maxValue);

注意:目前仅支持Comparables,不支持原始类型。 (你必须使用 Double 而不是 double)。

马文:

<dependency>
    <groupId>org.drombler.commons</groupId>
    <artifactId>drombler-commons-fx-core</artifactId>
    <version>0.7</version>
</dependency>

代码可在GitHub获取。

【讨论】:

  • 听起来正是我需要的。会调查它,也许会接受这个答案。
  • 从头开始实施属性实现几乎可以肯定是实现这一目标的方式。
【解决方案3】:

最简单的方法是这样做:

Math.max(min, Math.min(val, max));

这应该使小于最小值(0.0)的任何数字设置为最小值,并将任何大于最大值(1.0)的数字设置为最大值。

【讨论】:

  • 我明白,这不是我的问题。 Queston 是,我如何将它注入我的财产?
  • 这是一个 JavaFX 特定的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 2019-03-29
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多