Ввод числа в JSpinner с подклассом SpinnerListModel

Я хочу иметь 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 сохраняет все как целые числа, и это тоже работает. Поэтому я не уверен, почему мои целые числа не работают, но SpinnerNumberModel работает.


person Thunderforge    schedule 13.03.2013    source источник
comment
Пропустив код, JSpinner#commitEdit вызывает DefaultEditor#commitEdit (это получается приведением JSpinner#getEditor, иначе ничего не происходит), который вызывает DefaultEditor#getTextField()#comitEdit, который вызывает JFormattedTextField#getFormatter#stringToValue....так. Я думаю, из того набега. Я бы искал реализацию AbstractFormatter для вашей модели...: P   -  person MadProgrammer    schedule 13.03.2013
comment
Например, .   -  person trashgod    schedule 13.03.2013
comment
Итак, AbstractFormatter оказывается мостом между строкой, которую вводит пользователь, и фактическими значениями, содержащимися в базовом списке?   -  person Thunderforge    schedule 13.03.2013
comment
Я прочитал пример и обнаружил, что кажется, что все излишне усложняется, если просто сделать так, чтобы вы могли ввести число. Есть идеи, как это делает SpinnerNumberModel? Я хотел бы сделать это таким же образом.   -  person Thunderforge    schedule 13.03.2013
comment
Есть идеи, как это делает SpinnerNumberModel Как насчет того, чтобы прочитать его код :-) И @MadProgrammer уже подсказал, где искать, чтобы правильно получить коммит...   -  person kleopatra    schedule 13.03.2013
comment
Будучи новичком в Java, я не знаю, как читать код (Eclipse мне не позволяет). Но я уверен, что смогу разобраться.   -  person Thunderforge    schedule 14.03.2013
comment
в доме jdk есть src.zip, в Eclipse задача состоит в том, чтобы связать этот файл с rt.jar соответствующего установленного jdk: настройки --> установленный jres --> выберите один --> нажмите "Изменить" --> выберите rt.jar --> щелкните исходное вложение --> щелкните внешний файл --> выберите src.zip в соответствующем jdk   -  person kleopatra    schedule 14.03.2013


Ответы (2)


Я думаю, что следующее решение лучше, чем предложение реализовать Formatter, поскольку это не проблема форматирования, а проблема ограничения возможных значений, за которые должна нести ответственность модель. У меня была аналогичная проблема, и я наткнулся на решение этого потока, что привело к очень уродливой реализации. Так что, надеюсь, то, что я придумал, убережет вас от неприятностей.

Это прекрасно генерирует модель, и я могу перемещаться по значениям с помощью кнопок на JSpinner. Однако ввод значения не работает. Например, если счетчик установлен на 3 и я набираю 7, он остается на 3 (предположительно, потому что он не считает, что 7 является допустимым значением). Это работает с SpinnerNumberModel, поэтому я не уверен, что происходит.

Проблема здесь в том, что установка новой модели с помощью setModel имеет недокументированный побочный эффект изменения атрибута 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());
        }
    }
}
person phobic    schedule 02.08.2014

Я думаю, вы могли бы сделать это со строками, а затем использовать метод для получения числа. как это:

Spinner1(){
          String[] values={"1","3","5","7"};
          SpinnerModel model=new SpinnerListModel(values);
          JSpinner spinner=new JSpinner(model);
}
int getValue(Object obj){
    int out=0;
    return out=Integer.parseInt((String)obj);
}
person Ole van Santen    schedule 04.04.2013