javaswingbeans-binding

How to bind a JList to a Bean class property


I tried to bind a JList to a binding class property, Vector. In the binding class, the Vector is updated when a JTextField in UI is updated.

public void setName(String name) {
    String oldName = this.name;
    this.name = name;
    Vector oldList=this.list;
    list.add(name);
    propertySupport.firePropertyChange("name", oldName, this.name); //textField updates
    propertySupport.firePropertyChange(PROP_LIST, oldList, list); // JList
}

Also another seperate setter is available for updating the Vector. I have set add/remove PropertyChangeListeners as well.

My real requirement is to update the JList according to data in BeanBinding class. For example, when the user types in JTextField, relevant data from database and existing variables in class should be loaded into the JList.

Please, any one let me know how to bind data BeanBinding class (source) property for a JList in NetBeans. At least any tutorial link. There is a sample in NetBeans site, but it is for getting data directly from database.


Solution

  • Don't know about Netbeans, just menial coding :-) In that, wrap your list into an ObservableList and do all changes on the observable should work. Here's a runnable code snipped (sorry for the length, don't have the energy to strip it down right now)

    public class SimpleListBinding {
        @SuppressWarnings("unused")
        private static final Logger LOG = Logger
                .getLogger(SimpleListBinding.class.getName());
        private JComponent content;
        private JList list;
        private JTextField textField;
    
        private List<MyBean> beanList;
        private JButton modifyButton;
        private JButton addButton;
    
    
        /**
         * Binds list and simple properties.
         */
        private void bindBasics() {
            BindingGroupBean context = new BindingGroupBean();
            JListBinding listBinding = SwingBindings.createJListBinding(UpdateStrategy.READ_WRITE,
                    beanList, list);
            listBinding.setDetailBinding(BeanProperty.create("value"));
            context.addBinding(listBinding);
            context.addBinding(Bindings.createAutoBinding(UpdateStrategy.READ_WRITE,
                    list, BeanProperty.create("selectedElement.value"), 
                    textField,  BeanProperty.create("text")));
            context.bind();
            Action action = new AbstractAction("programatically change") {
                public void actionPerformed(ActionEvent e) {
                    int selectedBean = list.getSelectedIndex();
                    if (selectedBean < 0) return;
                    MyBean bean = beanList.get(selectedBean); 
                    bean.setValue(bean.getValue() + "*");
                }
    
            };
            modifyButton.setAction(action); 
    
            Action add = new AbstractAction("add bean") {
                int count = 0;
                @Override
                public void actionPerformed(ActionEvent e) {
                    beanList.add(new MyBean("added: " + count++));
                }
    
            };
            addButton.setAction(add);
        }
    
        private void initData() {
            MyBean[] beans = new MyBean[] {
                    new MyBean("first"), new MyBean("second"), new MyBean("third")
            };
            beanList = ObservableCollections.observableList(new ArrayList(Arrays.asList(beans)));
        }
    
        public static class MyBean extends AbstractBean {
            private String value;
            private boolean active;
            public MyBean(String value) {
                this.value = value;
            }
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                Object old = getValue();
                this.value = value;
                firePropertyChange("value", old, getValue());
            }
    
            public void setActive(boolean active) {
                boolean old = getActive();
                this.active = active;
                firePropertyChange("active", old, getActive());
            }
    
            public boolean getActive() {
                return active;
            }
        }
    
        private JComponent getContent() {
            if (content == null) {
                initComponents();
                content = build();
                initData();
                bindBasics();
            }
            return content;
        }
    
        private JComponent build() {
            JComponent comp = Box.createVerticalBox();
            comp.add(new JScrollPane(list));
            comp.add(textField, BorderLayout.SOUTH);
            comp.add(modifyButton);
            comp.add(addButton);
            return comp;
        }
    
        private void initComponents() {
            list = new JList();
            textField = new JTextField();
            modifyButton = new JButton("modify programmtically");
            addButton = new JButton();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    final JXFrame frame = new JXFrame("List binding", true);
                    frame.add(new SimpleListBinding().getContent());
                    frame.pack();
                    frame.setSize(400, 300);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
    }
    

    Edit: replaced JXList by JList (no difference in behaviour, just to make it compileable :-)