我想要一个JSpinner来显示数字的非模式序列(例如,质数序列)。对于SpinnerNumberModel来说,这种模式太复杂了,因此我决定将SpinnerListModel子类化。构造函数如下所示:

public CustomSpinnerListModel() {
    Vector<Integer> values = new Vector<Integer>();
    values.add(1);
    values.add(3);
    values.add(5);
    values.add(7);

    this.setList(values);
}

这样就可以很好地生成模型,我可以使用JSpinner上的按钮浏览各个值。但是,输入值无效。例如,如果微调器设置为3,而我键入7,则它将保持为3(大概是因为它认为7不是有效值)。这适用于SpinnerNumberModel,所以我不确定发生了什么。

编辑:我发现,如果我将数字另存为字符串值,则输入有效。但是,SpinnerNumberModel将所有内容保存为Integers,并且也可以使用。所以我不确定为什么我的整数不起作用,但是SpinnerNumberModel起作用。

最佳答案

我认为以下解决方案比实现Formatter的建议更好,因为这不是格式化问题,而是限制可能值的问题,这应该由模型负责。我有一个类似的问题,并且绊脚石这个线程解决方案,导致实现非常丑陋。因此,希望我提出的建议能使您摆脱麻烦。

这样就可以很好地生成模型,我可以使用JSpinner上的按钮浏览各个值。但是,输入值无效。例如,如果微调器设置为3,而我键入7,则它将保持为3(大概是因为它认为7不是有效值)。这适用于SpinnerNumberModel,所以我不确定发生了什么。

这里的问题是,使用setModel设置新模型具有未记录的副作用,该副作用取决于Model的类型来更改JTextFieldEditor属性:
http://fuseyism.com/classpath/doc/javax/swing/JSpinner-source.html

默认情况下,JSpinner使用SpinnerNumberModel类的模型以及DefaultNumberEditor类的编辑器。将模型设置为SpinnerListModel时,它将改为使用ListEditor。在您的情况下,这是一个糟糕的选择,因为它要求您将每个素数输入到列表中,然后将其提供给SpinnerListModel进行输入验证。否则,正如您所指出的,您的输入将被忽略。

因此,这里的简单解决方案是将SpinnerNumberModel子类化,该子类允许任何数字,而不是特定的值列表:

class PrimeNumberModel extends SpinnerNumberModel {
    Object currentValue;

    @Override
    public Object getNextValue() {
        return findNextPrimeFrom(currentValue);
    }

    @Override
    public Object getPreviousValue() {
        return findPreviousPrimeFrom(currentValue);
    }

    @Override
    public void setValue(Object o) {
        throwOnNonePrime(o); //Verify Input
        super.setValue(o);
    }

    private void throwOnNonePrime(Object o) {
        try {
            int num = Integer.valueOf(o.toString());
            if(!isPrime(num))
                throw new IllegalArgumentException(o.toString());
        } catch (NumberFormatException nfe) {
            throw new IllegalArgumentException(o.toString());
        }
    }
}

10-08 19:24