【问题标题】:Restrict which values will be settleable in an javafx property?限制哪些值可以在 javafx 属性中结算?
【发布时间】:2013-07-09 13:48:42
【问题描述】:

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

(如有必要,请帮我改善这篇文章可能不好的英文...)

【问题讨论】:

  • 在设置属性之前验证输入可能更简单,例如验证文本字段、数据库结果或文件中的数据。我看不出有什么好的方法来处理这个问题,你真的想要任何 #set() 调用来引发异常吗?
  • 您说得对:例如,为无法访问该列表的列表设置索引是没有意义的。但是,如果我可以访问列表,则 index 属性的设置器可能在列表本身中,并且该属性可能是只读的。在 List 中,如果索引超出范围,索引的设置器可能会抛出异常。

标签: java properties javafx javafx-2


【解决方案1】:

在您的两个示例中,似乎都有一个合乎逻辑的默认值(例如,如果要求为正,则负数变为 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 并自己实现设置/无效结构。

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

【讨论】:

  • 当然:如果输入可能是非法的,我需要一个布尔函数来检查输入是否非法。这不包含在 Javafx 属性中。
【解决方案2】:

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

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

  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 的系统代码设置故障保险。我会留下我之前的答案,因为我相信它也提供了有用的信息。

【讨论】:

  • 如果验证返回 false 并且我将属性恢复为 oldValue,验证将使用旧值作为“新”重新开始。如果oldValue 的验证也返回 false(可能是在添加验证侦听器之前属性中包含的值),我们进入一个循环。在这种情况下,在恢复它们之前验证 oldValue 会更安全。
猜你喜欢
  • 2011-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 1970-01-01
  • 2018-06-04
  • 2010-11-05
相关资源
最近更新 更多