Reputation: 20575
I want to have a JSpinner that displays an non-patterened sequence of numbers (say, a sequence of prime numbers). This pattern is too complicated for a SpinnerNumberModel, so I decided to subclass SpinnerListModel. The constructor looks something like this:
public CustomSpinnerListModel() {
Vector<Integer> values = new Vector<Integer>();
values.add(1);
values.add(3);
values.add(5);
values.add(7);
this.setList(values);
}
This generates the model just fine and I can move through the values using the buttons on the JSpinner. However, typing a value in doesn't work. For instance, if the spinner is set to 3 and I type in 7, it remains at 3 (presumably because it doesn't think that 7 is a valid value). This works with the SpinnerNumberModel, so I'm not sure what's going on.
EDIT: I found out that if I save the numbers as string values, typing works. However, SpinnerNumberModel saves everything as Integers and that works too. So I'm not sure why my integers don't work, but SpinnerNumberModel's do.
Upvotes: 3
Views: 459
Reputation: 1013
I think the following solution is better than the suggestion to implement a Formatter, as it is not a formatting issue, but an issue of restricting the possible values, which should be the responsibility of the model. I had a similar problem and stumbling upon this threads solution, lead to a very ugly implementation. So hopefully what I came up with will keep you out of trouble.
This generates the model just fine and I can move through the values using the buttons on the JSpinner. However, typing a value in doesn't work. For instance, if the spinner is set to 3 and I type in 7, it remains at 3 (presumably because it doesn't think that 7 is a valid value). This works with the SpinnerNumberModel, so I'm not sure what's going on.
The Problem here is that setting a new model with setModel has the undocumented side effect of changing the JTextFieldEditor attribute depending on the type of the Model: http://fuseyism.com/classpath/doc/javax/swing/JSpinner-source.html
By default, JSpinner uses a model of class SpinnerNumberModel with an editor of class DefaultNumberEditor. When you set the model to SpinnerListModel, it will instead use a ListEditor. In your case this is a bad choice, since it requires you to enter every prime number into a list to give it to the SpinnerListModel for input verification. Otherwise, as you pointed out, your input is ignored.
So the simple solution here is to subclass SpinnerNumberModel, which allows any number, instead of a specific list of values:
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());
}
}
}
Upvotes: 3
Reputation: 29
I think you could do it with strings and then use a method to get the number. like this:
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);
}
Upvotes: -1