First write adapter:
Code:
public class AsYouChangeSpinnerValue extends AbstractValueModelAdapter
implements ChangeListener, DocumentListener
{
private final JSpinner control;
private boolean settingNow;
public AsYouChangeSpinnerValue(JSpinner control, ValueModel valueModel)
{
super(valueModel);
Assert.notNull(control);
Assert.isTrue(control.getEditor() instanceof JSpinner.DefaultEditor,
"JSpinner editor must be instance of JSpinner.DefaultEditor");
this.control = control;
JSpinner.DefaultEditor editor = (DefaultEditor) control.getEditor();
editor.getTextField().getDocument().addDocumentListener(this);
control.addChangeListener(this);
initalizeAdaptedValue();
}
@Override
public void removeUpdate(DocumentEvent e)
{
controlValueChanged();
}
@Override
public void insertUpdate(DocumentEvent e)
{
controlValueChanged();
}
@Override
public void changedUpdate(DocumentEvent e)
{
controlValueChanged();
}
@Override
public void stateChanged(ChangeEvent e)
{
controlValueChanged();
}
private void controlValueChanged()
{
if(!settingNow)
{
adaptedValueChanged(control.getValue());
}
}
@Override
protected void valueModelValueChanged(Object value)
{
// this try block will coalesce the 2 DocumentEvents that
// JTextComponent.setText() fires into 1 call to
// componentValueChanged()
try
{
settingNow = true;
control.setValue(notNullValue(value));
} finally
{
settingNow = false;
}
}
private static Integer notNullValue(Object value)
{
if(value == null)
{
return Integer.valueOf(0);
}
return (Integer) value;
}
}
Second write binding:
Code:
public class IntegerSpinnerBinding extends AbstractBinding
{
private final JSpinner spinner;
protected IntegerSpinnerBinding(JSpinner spinner, FormModel formModel,
String formPropertyPath)
{
super(formModel, formPropertyPath, Integer.class);
this.spinner = spinner;
}
@Override
protected JComponent doBindControl()
{
final ValueModel valueModel = getValueModel();
try
{
if(valueModel.getValue() == null)
{
spinner.setValue(Integer.valueOf(0));
valueModel.setValue(Integer.valueOf(0));
}
else
{
spinner.setValue((Integer)valueModel.getValue());
}
}
catch (ClassCastException e)
{
IllegalArgumentException ex = new IllegalArgumentException(
"Class cast exception converting '"
+ getProperty()
+ "' property value to string - did you install a type converter?");
ex.initCause(e);
throw ex;
}
new AsYouChangeSpinnerValue(spinner, valueModel);
return spinner;
}
@Override
protected void readOnlyChanged()
{
//Disable editing from keyboard
//JFormattedTextField textField = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
//textField.setEditable(!isReadOnly());
spinner.setEnabled(!isReadOnly());
}
@Override
protected void enabledChanged()
{
spinner.setEnabled(isEnabled());
}
}
Third write binder:
Code:
public class IntegerSpinnerBinder extends AbstractBinder
{
public IntegerSpinnerBinder()
{
super(Integer.class);
}
@SuppressWarnings("unchecked")
@Override
protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context)
{
Assert.isTrue(control instanceof JSpinner, "Control must be an instance of JSpinner.");
JSpinner spinner = (JSpinner) control;
Binding binding = new IntegerSpinnerBinding(spinner, formModel, formPropertyPath);
AbstractBindingFactory bindingFactory = (AbstractBindingFactory) ((BindingFactoryProvider) getService(BindingFactoryProvider.class)).getBindingFactory(formModel);
bindingFactory.interceptBinding(binding);
return binding;
}
@SuppressWarnings("unchecked")
@Override
protected JComponent createControl(Map context)
{
return new JSpinner();
}
}
And now you can add spinner using tableformbuilder:
Code:
tableformbuilder.add(new IntegerSpinnerBinder().bind(jspinner,
getFormModel(), fieldName, Collections.EMPTY_MAP));
this code was written to use spinner for integer values only.