Results 1 to 5 of 5

Thread: Binding for JSpinner

  1. #1

    Question Binding for JSpinner

    After browsing the code base I see no support for binding to JSpinners. I know some people "dislike" JSpinners but how could they be left out of the framework entirely?

  2. #2
    Join Date
    Jul 2005
    Location
    Austria
    Posts
    105

    Default Use SwingBindingFactory

    SwingBindingFactory has a method to add a Spinner to your form. For example you have an attribute:
    Code:
    int runtime
    in your bean. Then you can make the following:
    Code:
      fb.add(sbf.createBoundSpinner("runtime"));
    but it do not works. There is still a JTextBox displayed. Looking at the SwingBindingFactory code, the method createBoundSpinner creates a JSpinner.class.

    Is this a bug, or must we write a custom binder?

    Thanks for advice
    markus

  3. #3
    Join Date
    Aug 2005
    Location
    Austin, TX
    Posts
    425

    Default

    At the moment, there is no binder for the JSpinner control. If you do end up writing one, could I whine and plead with you to submit an issue on it and include the code? I'd be happy to add it to the code base, but I just don't have the time to write one right now (although it should be very simple to do).

    Thanks,
    Larry.

  4. #4
    Join Date
    Oct 2009
    Posts
    1

    Default Binding, binder

    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.
    Last edited by urbanq; Oct 28th, 2009 at 09:20 AM.

  5. #5

    Default

    Will this code be published as part of the official release?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •