栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

JavaFX Spinner空文本nullpointerexception

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaFX Spinner空文本nullpointerexception

我在JDK源代码中流连忘返。

NPE从下面

if (newValue < getMin()) {
的侦听器lambda中抛出:

javafx.scene.control.SpinnerValueFactory.java

    public IntegerSpinnerValueFactory(@NamedArg("min") int min,     @NamedArg("max") int max,     @NamedArg("initialValue") int initialValue,     @NamedArg("amountToStepBy") int amountToStepBy) {        setMin(min);        setMax(max);        setAmountToStepBy(amountToStepBy);        setConverter(new IntegerStringConverter());        valueProperty().addListener((o, oldValue, newValue) -> { // when the value is set, we need to react to ensure it is a // valid value (and if not, blow up appropriately) if (newValue < getMin()) {      setValue(getMin()); } else if (newValue > getMax()) {     setValue(getMax()); }        });        setValue(initialValue >= min && initialValue <= max ? initialValue : min);    }

大概

newValue
null
null
NPE
的自动拆箱。由于输入来自编辑器,因此我怀疑
IntegerStringConverter
哪个是默认转换器。

在这里查看实现:

javafx.util.converter.IntegerStringConverter

public class IntegerStringConverter extends StringConverter<Integer> {        @Override public Integer fromString(String value) {        // If the specified value is null or zero-length, return null        if (value == null) { return null;        }        value = value.trim();        if (value.length() < 1) { return null;        }        return Integer.valueOf(value);    }        @Override public String toString(Integer value) {        // If the specified value is null, return a zero-length String        if (value == null) { return "";        }        return (Integer.toString(((Integer)value).intValue()));    }}

我们看到它将很高兴地返回

null
空字符串,考虑到输入不存在有效值,这是合理的。

跟踪调用堆栈,我发现值从何而来:

javafx.scene.control.Spinner

public Spinner() {    getStyleClass().add(DEFAULT_STYLE_CLASS);    setAccessibleRole(AccessibleRole.SPINNER);    getEditor().setonAction(action -> {        String text = getEditor().getText();        SpinnerValueFactory<T> valueFactory = getValueFactory();        if (valueFactory != null) { StringConverter<T> converter = valueFactory.getConverter(); if (converter != null) {     T value = converter.fromString(text);     valueFactory.setValue(value); }        }    });

用从转换器获得的值设置该值,该值

T value =converter.fromString(text);
可能为空。在这一点上,我相信Spinner类应该检查
value
是否存在
null
,是否将先前的值恢复到编辑器。

我现在相当确定这是一个错误。此外,我认为使用永远不会返回null的转换器来解决问题不会正常工作,因为它只会掩盖问题,并且在无法转换值时应返回什么值?

编辑:解决方法

onAction
用“返回有效”策略替换微调框编辑器的拒绝无效输入可解决此问题:

public static <T> void fixSpinner2(Spinner<T> aSpinner) {    aSpinner.getEditor().setonAction(action -> {        String text = aSpinner.getEditor().getText();        SpinnerValueFactory<T> factory = aSpinner.getValueFactory();        if (factory != null) { StringConverter<T> converter = factory.getConverter(); if (converter != null) {     T value = converter.fromString(text);     if (null != value) {         factory.setValue(value);     }     else {         aSpinner.getEditor().setText(converter.toString(factory.getValue()));     } }        }        action.consume();    });}

与侦听器相反,

valueProperty
这避免了使用无效数据触发其他侦听器。但是,这突出了旋转器类中的另一个问题。上面的方法通过按Enter返回有效值来解决问题。删除输入而不提交(按Enter),然后按递增或递减将导致相同的NPE,但调用堆栈略有不同。

原因:

public void increment(int steps) {    SpinnerValueFactory<T> valueFactory = getValueFactory();    if (valueFactory == null) {        throw new IllegalStateException("Can't increment Spinner with a null SpinnerValueFactory");    }    commitEditorText();    valueFactory.increment(steps);}

减量类似,两者都称为

commitEditorText

private void commitEditorText() {    if (!isEditable()) return;    String text = getEditor().getText();    SpinnerValueFactory<T> valueFactory = getValueFactory();    if (valueFactory != null) {        StringConverter<T> converter = valueFactory.getConverter();        if (converter != null) { T value = converter.fromString(text); valueFactory.setValue(value);        }    }}

注意

onAction
构造器中的复制粘贴:

    getEditor().setonAction(action -> {        String text = getEditor().getText();        SpinnerValueFactory<T> valueFactory = getValueFactory();        if (valueFactory != null) { StringConverter<T> converter = valueFactory.getConverter(); if (converter != null) {     T value = converter.fromString(text);     valueFactory.setValue(value); }        }    });

我相信

commitEditorText
应该将其更改为
onAction
在编辑器上触发,如下所示:

private void commitEditorText() {    if (!isEditable()) return;    getEditor().getonAction().handle(new ActionEvent(this, this));}

那么行为将是一致的,并使编辑者有机会在输入值工厂之前对其进行处理。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/509530.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号