Announcement Announcement Module
Collapse
No announcement yet.
How to do simple list bindings Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to do simple list bindings

    I am a RCP newbie, and I am trying to build some forms. Does anyone have some examples based on the latest source code that show how to add lists to a form? What I am looking for is an example with basic list bindings, and I believe some of the previous examples from the forum don't work due to the latest code changes (from what I have tried). For example, I want to do something like this:

    The domain class:

    Code:
    public class Project{
    	String name;
    	String[] members;
    	String manager;
    	....
    }
    Suppose in the GUI that I want a textfield to map to the name, a JList containing a list of employees' names to map members, and a comboBox containing all the employees' names to map to the manager. I assume this is a fairly trivial example that would get one started on how to do this. Here is my start on this, but how is one supposed to bind the list of available names to a JList? I saw how in the PetStore app the PetTypes are bound to the PetType, but in this case where I may have lots of lists of type string, I assume there is an easy way to do this.

    Code snippet where form is created:

    Code:
    {
    
            JPanel view = new JPanel...
            Project project = new Project();
            FormModel projectModel = FormModelHelper.createFormModel(project);
            ProjectForm projectForm = new ProjectForm(projectModel, "projectForm");
            view.add(projectForm.createFormControl());
            ...
    }
    
    
    // Here is the form, without Bindings
    
    public class ProjectForm extends AbstractForm {
        
        public ProjectForm(FormModel formModel, String formId) {
            super(formModel, formId);
        }
        
    
        protected JComponent createFormControl() {
            List employees = new ArrayList();
            employees.add...Add some names e.g. "Bill", "Ted", "Mary", "Willy" 
            
            // how to bind the employees names to the fields for JList and Combobox???
            
            // Build the form
            TableFormBuilder formBuilder = new TableFormBuilder(getBindingFactory());
    
            formBuilder.addSeparator("Project Information");
            formBuilder.row();
            formBuilder.add("name");
            formBuilder.row();
            formBuilder.add("members");
            formBuilder.row();
            formBuilder.add("manager");
            return formBuilder.getForm();
        }
    }
    Thanks for any help.

    Tom

  • #2
    Try casting the BindingFactory returned from getBindingFactory() to SwingBindingFactory:
    Code:
    SwingBindingFactory bf = (SwingBindingFactory)getBindingFactory();
    You will then find methods for binding to lists and comboboxes (createBoundComboBox(...), createBoundList(...), etc). These methods will return a Binding that can provide you with an actual component to add to your form. Here is a complete example:
    Code:
        protected JComponent createFormControl()
        {
          final SwingBindingFactory sbf = (SwingBindingFactory)getBindingFactory();
          final TableFormBuilder fb = new TableFormBuilder(sbf);
         
          fb.add("reportDescription");
          fb.row();
          fb.add("groupId");
          fb.row();
          fb.add("reportId");
          fb.row();
          fb.add("defaultReport");
          fb.row();
          fb.addSeparator("reportUploadForm.separator.selectRoles");
          fb.row();
          fb.add("reportRoles", new JScrollPane(sbf.createBoundList("reportRoles", getAvailableRoles(), "name").getControl()));
          fb.row();
          fb.addSeparator("reportUploadForm.separator.selectFile");
          fb.row();
          fb.add("reportFile");
          return fb.getForm();
        }
    Which is based on this bean:
    Code:
      public class ReportDescriptor implements PropertyConstraintProvider
      {
        private String reportDescription;
        private String groupId;
        private String reportId;
        private boolean defaultReport = true;
        private List<Role> reportRoles = new ArrayList<Role>&#40;&#41;;
        private File reportFile;
        ...
      &#125;
    Note that since the "selectionFormProperty" is a Collection (List<Role>), the binding method in SwingBindingFactory will automatically create a multiple selection list. If the selectionFormProperty were not a collection (maybe just a Role reference), then the List would allow only single selection. There is a method in SwingBindingFactory that allows to override this as well.

    - Andy

    Comment


    • #3
      Thanks for the example Andy. One caveat I am experiencing is the following line:

      Code:
      fb.add&#40;"reportRoles", new JScrollPane&#40;sbf.createBoundList&#40;"reportRoles", getAvailableRoles&#40;&#41;, "name"&#41;.getControl&#40;&#41;&#41;&#41;;
      When this is attempted, the BindingFactory is attempting to bind "reportRoles" with a JTextComponent because it doesn't have a binding mapptng for the JScrollPane (hope I am interpreting this correctly). If I just create the binding and add it directly, it does display my list, e.g.

      Code:
      Binding reportRoleBinding = sbf.createBoundList&#40;"reportRoles", getAvailableRoles&#40;&#41;, "name"&#41;;
      fb.add&#40;reportRoleBinding&#41;;
      Did you perhaps modify or extend your BindingFactory to support JScrollPane or do something to make this work, or am I just missing something.

      BTW, here is the logging and stacktrace where the binding is being resolved. Note that in the example I am working with, my list is called "stations" instead of "reportRoles", and the bean is called TrafficSearchCriteria, but other than that example is the same:

      2005-07-06 09:54:58,871 DEBUG org.springframework.util.CachingMapTemplate Caching key value pair 'stations' -> 'org.springframework.binding.support.BeanPropertyA ccessStrategy$BeanPropertyValueModel@1f8f8c8'
      2005-07-06 09:54:58,871 DEBUG org.springframework.binding.form.support.Validatin gFormModel Creating form value buffer for property 'stations'
      2005-07-06 09:54:58,887 DEBUG org.springframework.beans.BeanWrapperImpl About to invoke read method [public java.util.List us.oh.state.dot.tko.gui.TrafficSearchCriteria.getS tations()] on object of class [us.oh.state.dot.tko.gui.TrafficSearchCriteria]
      2005-07-06 09:54:58,902 DEBUG org.springframework.binding.form.support.Validatin gFormModel Registering 'stations' form property, property value model=org.springframework.binding.form.support.Val idatingFormModel$ValidatingFormValueModel@ffc3eb
      2005-07-06 09:54:58,918 DEBUG org.springframework.beans.factory.support.DefaultL istableBeanFactory Returning cached instance of singleton bean 'binderSelectionStrategy'
      2005-07-06 09:54:58,918 DEBUG org.springframework.beans.factory.support.DefaultL istableBeanFactory Returning cached instance of singleton bean 'componentFactory'
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through [interface javax.swing.ScrollPaneConstants, interface javax.accessibility.Accessible]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class javax.swing.JComponent
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through [interface java.io.Serializable]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class java.awt.Container
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class java.awt.Component
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through [interface java.awt.image.ImageObserver, interface java.awt.MenuContainer, interface java.io.Serializable]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class java.lang.Object
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils Could not find a definition for class javax.swing.JScrollPane in [class javax.swing.JComboBox, class javax.swing.JCheckBox, class javax.swing.JFormattedTextField, class javax.swing.JTextArea, class javax.swing.text.JTextComponent, class javax.swing.JList, class javax.swing.JLabel]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class java.lang.Object
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils Could not find a definition for class us.oh.state.dot.tko.gui.TrafficSearchCriteria in []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through [interface java.util.Collection]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils Could not find a definition for interface java.util.List in [class java.lang.Boolean, class java.util.Date, interface org.springframework.core.enums.LabeledEnum, boolean, class java.lang.String]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through [interface javax.swing.SwingConstants]
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching through []
      2005-07-06 09:54:58,996 DEBUG org.springframework.richclient.util.ClassUtils searching for class javax.swing.text.JTextComponent
      2005-07-06 09:54:59,012 ERROR org.springframework.richclient.application.config. ApplicationLifecycleAdvisor Control must be an instance of JTextComponent.
      java.lang.IllegalArgumentException: Control must be an instance of JTextComponent.
      at org.springframework.util.Assert.isTrue(Assert.java :64)
      at org.springframework.richclient.form.binding.swing. TextComponentBinder.doBind(TextComponentBinder.jav a:38 )
      at org.springframework.richclient.form.binding.suppor t.AbstractBinder.bind(AbstractBinder.java:86)
      at org.springframework.richclient.form.binding.suppor t.AbstractBindingFactory.bindControl(AbstractBindi ngFactory.java:84)
      at org.springframework.richclient.form.binding.suppor t.AbstractBindingFactory.bindControl(AbstractBindi ngFactory.java:62)
      at org.springframework.richclient.form.builder.Abstra ctFormBuilder.getBinding(AbstractFormBuilder.java: 76)
      at org.springframework.richclient.form.builder.TableF ormBuilder.add(TableFormBuilder.java:70)
      at org.springframework.richclient.form.builder.TableF ormBuilder.add(TableFormBuilder.java:66)
      at us.oh.state.dot.tko.gui.TrafficSearchForm.createFo rmControl(TrafficSearchForm.java:46)
      at us.oh.state.dot.tko.gui.TrafficDataView.createCont rol(TrafficDataView.java:57)
      at org.springframework.richclient.factory.AbstractCon trolFactory.getControl(AbstractControlFactory.java :48 )


      Thanks for the help, Tom

      Comment


      • #4
        Yep, you're right - I forgot that I had been playing with some local mods. As it stands now, I don't see a way to get that scroll pane in there without some custom binding... hmm.. I wonder what the best way to approach this would be? I would like to arbitrarily wrap some component returned from a binding in another component before actually adding it to a form, but the form builder assumes that the actual component being added to the form must have a binding directly associated with it. Probably the easiest way to approach it at this point would be a binding wrapper:
        Code:
         public class DecoratedControlBinding implements Binding
        &#123;
          private final Binding source;
          private final JComponent decoratingComponent;
        
          public DecoratedControlBinding&#40;final Binding source, final JComponent decoratingComponent&#41;
          &#123;
            this.source = source;
            this.decoratingComponent = decoratingComponent;
          &#125;
        
          public Binding getSource&#40;&#41;
          &#123;
            return this.source;
          &#125;
        
          public JComponent getDecoratingComponent&#40;&#41;
          &#123;
            return this.decoratingComponent;
          &#125;
        
        
          //
          // METHODS FROM INTERFACE Binding
          //
        
          public FormModel getFormModel&#40;&#41;
          &#123;
            return getSource&#40;&#41;.getFormModel&#40;&#41;;
          &#125;
        
          public String getProperty&#40;&#41;
          &#123;
            return getSource&#40;&#41;.getProperty&#40;&#41;;
          &#125;
        
          public JComponent getControl&#40;&#41;
          &#123;
            getSource&#40;&#41;.getControl&#40;&#41;;
            return getDecoratingComponent&#40;&#41;;
          &#125;
        &#125;
        Note, I haven't tested this yet (I'm doing this off the top of my head in this message), but if it works, you should be able to then do this:

        Code:
              Binding rolesBinding = sbf.createBoundList&#40;"reportRoles", getAvailableRoles&#40;&#41;, "name"&#41;;
              JScrollPane rolesScrollpane = new JScrollPane&#40;rolesBinding.getControl&#40;&#41;&#41;;
              fb.add&#40;new DecoratedControlBinding&#40;rolesBinding, rolesScrollpane&#41;&#41;;
        Also note that I call getSource().getControl() in DecoratedControlBinding.getControl(). This is just a safeguard to ensure that the source's getControl() has been invoked since it sometimes does initialization.
        If decorating components in scroll panes becomes common, you could even create another class:
        Code:
        public class ScrollpaneDecoratedBinding extends DecoratedControlBinding
        &#123;
          public ScrollpaneDecoratedBinding&#40;final Binding source&#41;
          &#123;
            super&#40;source, new JScrollPane&#40;&#41;&#41;;
            &#40;&#40;JScrollPane&#41;getDecoratingComponent&#40;&#41;&#41;.setViewportView&#40;getSource&#40;&#41;.getControl&#40;&#41;&#41;;
          &#125;
        &#125;
        Then, you could just do this:

        Code:
              fb.add&#40;new ScrollpaneDecoratedBinding&#40;sbf.createBoundList&#40;"reportRoles", getAvailableRoles&#40;&#41;, "name"&#41;&#41;&#41;;

        - Andy

        Comment


        • #5
          Note, I may add this to Spring-rich if Oliver doesn't think it's too messy.

          - Andy

          Comment


          • #6
            FYI, the DecoratedControlBinding approach works . Guess I'll see if Oliver has another approach or if you can add this to the Spring Rich source code.

            Something like this will have to be supported somehow, since developers are going to want to decorate controls for sure. The current approach seems to suggest that one should create custom bindings like the CalendarDateBinder from Pet Store, but that seems overkill for something like this. And if I understand correctly (and I may not), in that approach we'd have to create bindings for a JList with a ScrollPane for example, as well as other different controls that have a ScrollPane or whatever. Alternatively, convenience methods could be added to the SwingBindingFactory, but boy we already have alot of create methods there as it is. Well, for now this is a handy work around if nothing else.

            Thanks, Tom

            Comment


            • #7
              I've added DecoratedControlBinding and ScrollPaneDecoratedBinding to org.springframework.richclient.form.binding.suppor t. I've also added a convenience contructor to ScrollPaneDecoratedBinding (for setting scrollbar policies). While I was at it, I added some scroll pane creation methods to ComponentFactory and rewrote ScrollPaneDecoratedBinding to use Application.services().getComponentFactory().creat eScrollPane(...) instead of directly instantiating a new JScrollPane.
              Finally (and best of all for my code, anyway), I've added some convenience methods to TableFormBuilder that utilize ScrollPaneDecoratedBinding:
              Code:
                  public JComponent&#91;&#93; addInScrollPane&#40;String propertyName&#41;;
                  public JComponent&#91;&#93; addInScrollPane&#40;String propertyName, String attributes&#41;; 
                  public JComponent&#91;&#93; addInScrollPane&#40;Binding binding&#41;;
                  public JComponent&#91;&#93; addInScrollPane&#40;Binding binding, String attributes&#41;;
              These methods will take the supplied Binding (or the default Binding for the specified property) and wrap it in a ScrollPaneDecoratedBinding before adding to the form. I can now do this in my code:

              Code:
              fb.addInScrollPane&#40;sbf.createBoundList&#40;"reportRoles", getAvailableRoles&#40;&#41;, "name"&#41;&#41;;
              - Andy

              Comment

              Working...
              X