6

将 javafx 属性的值保持在特定范围内的最佳方法是什么?

(或者 - 这是一种不好的做法,是否存在从不过滤由 javafx 属性包装的值的任何理由?)

示例 1:避免 IntegerProperty 中的负值示例 2:将 IntegerProperty
的值保持在 List 的范围内

第一个想法:-覆盖IntegerPropertyBase.set(int)。它是安全的?实际上setValue(int)只调用set(int),但是 - 如果有一天这个实现发生变化 - 对值集的控制就会丢失。

第二个想法:-覆盖IntegerPropertyBase.invalidate()。但是此时已经设置了值。

它是否更适合 javafx 属性抛出一个IllegalArgumentException(或一个ArrayIndexOutOfBoundsException,如果包装的值是数组的索引),或者更好地拒绝超出范围的值,设置回边界中的最后一个值?

也许是这样的:

    class BoundedIntegerProperty extends IntegerPropertyBase {
        (...)
        int oldValue = defaultValueInBounds;
        boolean settingOldValue = false;
        public void invalidated() {
            if(!settingOldValue){
                if(outOfBounds(get())){
                    settingOldValue = true;
                    set(oldValue);
                } else {
                    oldValue = get();
                }
            } else
                settingOldValue = false;
        }
    }

仅在 invalidated() 中为超出范围的值抛出异常可能会使属性的值超出范围。

我是否忽略了为过滤值而提供的 javafx 属性中的任何内容?

(如有必要,请帮助我改进本文可能不好的英文......)

4

2 回答 2

2

在您的两个示例中,似乎都有一个逻辑默认值(例如,如果它需要为正数,则负数变为 0)。假设您记录得很好(如果值无效,默认值是什么),我认为您的第一种方法似乎是在正确的道路上。

我建议从一个具体SimpleIntegerProperty的类开始,比如你要扩展的类(除非你选择了某些原因IntegerPropertyBase

然后我将覆盖set(int)方法和setValue(Number)方法,将父级包装在您的逻辑中:

    /**
     * Explanation that values under 0 are set to 0
     */
    @Override
    public void set(int value){
        super.set(value > 0 ? value : 0);
    }

    /**
     * Explanation that values under 0 are set to 0
     */
    @Override
    public void setValue(Number value){
        super.setValue(value.intValue() > 0 ? value : 0);
    }

可能存在没有逻辑默认值的情况(或者您只想拒绝无效值)。这种情况让它变得有点困难——你实际上想要使用这样的方法签名,这样调用者就知道值是否改变了:

public boolean set(int value)

为了做到这一点,您必须返回很多类 - 一直返回ReadOnlyIntegerProperty并自己实现设置/无效结构。

我会犹豫使用异常来处理无效输入。这是对异常的合法使用,但我担心异常会被依赖于验证。异常是非常耗费资源的,只有在需要修复某些东西时才应该被击中。因此,这实际上与您的意图以及您对使用您的课程的人做正确事情的信任程度有关(并在发送给您之前进行验证)。

于 2013-07-17T17:08:17.637 回答
1

我相信我现在更了解你的目标了。您正在寻找执行用户输入验证。

当您进行用户验证时,实际上有两种方法可以处理它:

  1. 任何更改发生后立即验证并提供反馈
  2. 验证焦点何时离开输入区域

对于这两者,您将使用属性侦听器 - 这只是您正在处理的属性侦听器的问题。

在第一种情况下,您将直接收听您正在验证的属性:

    TextField field = new TextField();
    field.textProperty().addListener(new ChangeListener<String>(){
        @Override
        public void changed(ObservableValue<? extends String> value,
                String oldValue, String newValue) {
                //Do your validation or revert the value
        }});

在第二种情况下,您将侦听该focused属性,并在失去焦点时进行验证(您可以在此侦听器中维护最后验证的值,以帮助在必要时恢复该值):

    TextField field = new TextField();
    field.focusedProperty().addListener(new ChangeListener<Boolean>(){
        String lastValidatedValue = "";
        @Override
        public void changed(ObservableValue<? extends Boolean> value,
                Boolean oldValue, Boolean newValue) {
            if(newValue == false && oldValue == true){
                //Do your validation and set `lastValidatedValue` if valid
            }
        }});

注意: 我假设您只是想为更新 UI 的系统代码设置故障保护。我会留下我之前的答案,因为我相信它也提供了有用的信息。

于 2013-07-30T20:34:23.370 回答