限制哪些值可以在javafx属性中解决?

时间:2013-07-11 10:19:31

标签: java properties javafx javafx-2

将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属性中的任何内容?

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

2 个答案:

答案 0 :(得分: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并自己实现设置/无效结构。

我会犹豫使用Exceptions来处理无效输入。它是异常的合法使用,但我担心异常将依赖于验证。例外是非常耗费资源的,只有在需要修复的情况下才能触及。所以它真的是关于你的意图以及你有多少信任人们使用你的班级来做正确的事情(并在发送给你之​​前进行验证)。

答案 1 :(得分:1)

我相信我现在明白你的目标是什么。您正在寻求执行用户输入验证。

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

  1. 在发生任何变更后立即进行验证并提供 反馈
  2. 在焦点离开输入区域时验证
  3. 使用两者,你​​将使用属性监听器 - 这只是你正在处理的属性监听器的问题。

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

        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安装一个故障保险箱。我会留下我以前的答案,因为我相信它也提供了有用的信息。