Geertjan is a DZone Zone Leader and has posted 453 posts at DZone. You can read more from them at their website. View Full User Profile

Hello BeansBinding on the NetBeans Platform

01.18.2009
| 12632 views |
  • submit to reddit

Without typing a single line of code, you can integrate JSR 295, the Beans Binding Framework, into a NetBeans Platform application. (Whether you want to do so is a separate question, now that this JSR will apparently not be in JDK 7, while JavaFX contains something similar [and even more effective than JSR-295, in terms of simplicity].) Nevertheless, ignoring those two details for the moment, let's see how easy it is to "implement" Beans Binding on the NetBeans Platform.

  1. Create a new NetBeans module. In my case, I called the module "BBDemo", with code name base "org.netbeans.bbdemo". No need to let the wizard create a "layer.xml", because we will create a new TopComponent and , in doing so, the New Window Component wizard will create that file for us.

  2. Create a new TopComponent, after stepping through the New Window Component wizard. Do this by right-clicking the project node that is created at the end of the previous step, and then choosing New File. In the New File dialog, choose Module Development | Window Component. Accept all the defaults, setting "Demo" as the class name prefix.

  3. Drag and drop a JSlider onto the TopComponent. Do this from the Palette, which you can open by clicking Ctrl-Shift-8.

  4. In the same way, drag and drop a JTextField above the JSlider on the TopComponent. Resize the TopComponent a bit to make everything fit snugly, with this result:

  5. Now we'll connect them without the tedious listener-code that is typically required for this purpose. Right-click the JTextField and choose Bind | Text. In the dialog that appears, choose "jSlider1" in "Binding Source", which will enable you to choose "value" in "Binding Expression". You should now see this:

  6. Right-click the module, choose Properties, and go to the Libraries tab. There, click Add, type 'binding', and then you will see the Beans Binding integration module filtered at the top of the list. Yes, the Beans Binding JAR is just one of the many JARs available to you in the form of modules in the NetBeans module system. Click OK and then OK again to confirm that you want to use this library.

Notice that the JTextField is filled with the default value of the JSlider, indicating that the two Swing components are connected. Run the module (right-click the module and choose Run). The IDE will start a new NetBeans IDE instance and you will see your new window with the two Swing components connected. In other words, change something in the JSlider and the JTextField will automatically be updated:

No listeners have been set, only beans bindings between the two components. Study the generated code (in the Source view of the TopComponent) to see what's going on.

Hurray, done. Now wasn't that easy? Next time we'll apply these principles to the database scenario outlined in yesterday's "Hello EclipseLink on the NetBeans Platform" article.

 

 

AttachmentSize
fig-1-bb.png6.07 KB
fig-2-bb.png9.24 KB
fig-3-bb.png4.03 KB
Published at DZone with permission of its author, Geertjan Wielenga.

Comments

Peter Levart replied on Sun, 2009/01/18 - 5:46pm

[quote](Whether you want to do so is a separate question, now that this JSR will apparently not be in JDK 7, while JavaFX contains something similar [and even more effective than JSR-295, in terms of simplicity].)[/quote]

Whether JSR-295 (and JSR-296, the app. framework) will still be supported and perhaps support for them even improved in future NetBeans versions is a question. The answer perhaps depends on whether their development will continue. And that depends more or less on Sun's politics. I don't mind that they will not be included in JDK 7. I would regret if their development stopped. Does anybody have any inside information about the plans for supporting those two frameworks in future NetBeans? The support for JSR-295 could be improved. For example the "binding editor dialogs" are currently not updated when Java classes change (new properties added for example) and you have to restart NetBeans to pick up changes. Otherwise it is quite useable and I have already created a couple of UIs with NetBeans using solely JSR-295 and JSR-296.

Peter

 

Miguel Garcia-lopez replied on Mon, 2009/01/19 - 5:23am

Dear Geertjan, nice post as usual. Although it gives a good hint on how to use BB's within NB IDE, it's also quite a very straightforward scenario. May I pose a more ellaborate one, which in fact I have not been able to solve in my application (nor found any solution on the web):

  public enum GraphKind { BAR_CHART, CONTINUOUS_CHART, PLOT_CHART; }

  public class GraphManager { private GraphKind graphKind; // [get & set methods] }

Build a simple Matisse GUI with three radio buttons:

  private JRadioButton useBarChartRadioButton;

  private JRadioButton useContChartRadioButton;

  private JRadioButton usePlotChartRadioButton;

  // [Connect these three buttons with a Button Group, too]

Now, any chance to bind the buttons to the "graphKind" field, in a similar way you describe in the post, all within the IDE?

I am aware this is more a "cry for help" thing than a regular blog post comment, so feel free to ignore ;)

Richard Osbaldeston replied on Mon, 2009/01/19 - 6:05am in response to: Peter Levart

I doubt you're going to get an answer to the future of JSR295 in here. The right place to ask would be the beanbindings project mailing lists. Not that'd you necessarily get an answer even there: http://beansbinding.dev.java.net/servlets/ReadMsg?list=users&msgNo=652

Personally I wouldn't touch JSR 295 any more, it's not been developed in over a year and apparently won't continue development in it's current form. It's not supported, undocumented, lacks unit tests, incomplete, it leaks and its slow.

Future plans seem to tie beansbindings to language-level properties support (also abandoned) and a whole new JavaBean spec (unwritten) but possibly re-integrating Java and JavaFX. These aren't even pencilled into any JDK release AFAIK. I honestly don't think there are any answers to be had. But Sun would much rather developers got into JavaFX Script than try to re-engineer the existing APIs. It's probably fair to say the new JavaFX component set will be here (jfx2.0? 2010?) well before beansbindings is on the table again.

Peter Levart replied on Mon, 2009/01/19 - 5:25pm in response to: Miguel Garcia-lopez

Well, without code I doubt it can be done.

I for exampe had the same problem and created an extended "EnumButtonGroup" to solve it. It is used simply like this:

 

        EnumButtonGroup<FindInvoicesRestriction> ebg = new EnumButtonGroup<FindInvoicesRestriction>(FindInvoicesRestriction.class);
ebg.add(FindInvoicesRestriction.ALL, includeAllRadioButton);
ebg.add(FindInvoicesRestriction.REVERSABLE, includeReversibleRadioButton);
ebg.add(FindInvoicesRestriction.WORKING_COPIES, includeWorkingCopiesRadioButton);
ebg.assertButtonGroupCoversAllEnumConstants();

bindingGroup.addBinding(Bindings.createAutoBinding(
UpdateStrategy.READ_WRITE,
this, ELProperty.create("${query.restriction}"),
ebg, EnumButtonGroup.SELECTED_ENUM_PROPERTY
));

bindingGroup.bind();

 

 

The EnumButtongGroup I cerated is as follows:

 

import com.google.common.base.Preconditions;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Property;

import javax.swing.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.*;

/**
 * This work is hereby released into the Public Domain.
 * To view a copy of the public domain dedication,
 * visit http://creativecommons.org/licenses/publicdomain/
 * or send a letter to Creative Commons, 171 Second Street,
 * Suite 300, San Francisco, California, 94105, USA.
 *
 * @author Peter Levart
 */
public class EnumButtonGroup<E extends Enum<E>> extends ButtonGroup
{
    private Map<E, AbstractButton> enum2button;
    private Map<ButtonModel, E> buttonModel2enum = new HashMap<ButtonModel, E>();
    private PropertyChangeSupport pcs;
    private Class<E> enumType;

    public EnumButtonGroup(Class<E> enumType)
    {
        this.enumType = Preconditions.checkNotNull(enumType);
        enum2button = new EnumMap<E, AbstractButton>(enumType);
    }

    public void add(E e, AbstractButton b)
    {
        Preconditions.checkNotNull(e);
        Preconditions.checkNotNull(b);

        if (enum2button.containsKey(e))
            throw new IllegalStateException("Enum value: " + e + " is already associated with this button group");

        if (buttonModel2enum.containsKey(b.getModel()))
            throw new IllegalStateException("Given button is already part of this button group");

        enum2button.put(e, b);
        buttonModel2enum.put(b.getModel(), e);

        super.add(b);
    }

    public AbstractButton remove(E e)
    {
        Preconditions.checkNotNull(e);

        AbstractButton b = enum2button.get(e);
        if (b == null)
            return null;

        super.remove(b);

        enum2button.remove(e);
        buttonModel2enum.remove(b.getModel());

        return b;
    }

    public void assertButtonGroupCoversAllEnumConstants()
    {
        Set<E> fullSet = EnumSet.allOf(enumType);
        if (fullSet.size() != enum2button.size())
            throw new AssertionError("ButtonGroup only has the following enum constants associated: " + enum2button.keySet() + " but it was asserted that it covers all of them: " + fullSet);
    }

    @Deprecated
    @Override
    public void add(AbstractButton b)
    {
        throw new UnsupportedOperationException("use add(E, AbstractButton) instead");
    }

    @Deprecated
    @Override
    public void remove(AbstractButton b)
    {
        throw new UnsupportedOperationException("use remove(E) instead");
    }

    @Override
    public void setSelected(ButtonModel m, boolean b)
    {
        ButtonModel oldSelection = getSelection();
        super.setSelected(m, b);
        fireSelectedEnumPropertyChange(oldSelection, getSelection());
    }

    @Override
    public void clearSelection()
    {
        ButtonModel oldSelection = getSelection();
        super.clearSelection();
        fireSelectedEnumPropertyChange(oldSelection, getSelection());
    }


    private PropertyChangeSupport pcs()
    {
        if (pcs == null)
            pcs = new PropertyChangeSupport(this);

        return pcs;
    }

    public void addPropertyChangeListener(PropertyChangeListener listener)
    {
        pcs().addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener)
    {
        pcs().removePropertyChangeListener(listener);
    }

    public PropertyChangeListener[] getPropertyChangeListeners()
    {
        return pcs().getPropertyChangeListeners();
    }

    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
    {
        pcs().addPropertyChangeListener(propertyName, listener);
    }

    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
    {
        pcs().removePropertyChangeListener(propertyName, listener);
    }

    public PropertyChangeListener[] getPropertyChangeListeners(String propertyName)
    {
        return pcs().getPropertyChangeListeners(propertyName);
    }

    public boolean hasListeners(String propertyName)
    {
        return pcs().hasListeners(propertyName);
    }

    private void fireSelectedEnumPropertyChange(ButtonModel oldSelection, ButtonModel newSelection)
    {
        pcs().firePropertyChange("selectedEnum", buttonModel2enum.get(oldSelection), buttonModel2enum.get(newSelection));
    }


    public static final Property SELECTED_ENUM_PROPERTY = BeanProperty.create("selectedEnum");
    
    public E getSelectedEnum()
    {
        return buttonModel2enum.get(getSelection());
    }

    public void setSelectedEnum(E e)
    {
        AbstractButton b = enum2button.get(e);
        if (b == null)
            clearSelection();
        else
            setSelected(b.getModel(), true);
    }
}

 

Miguel Garcia-lopez replied on Mon, 2009/01/19 - 10:56am

That's such a useful answer, thanks so much!

I assume by sharing your code here I may be able to adapt it for my project, may you please confirm? No problem granting you any mention or whatever within. 

And, yes, I do also think something should be done regarding beansbinding support into the JRE and/or at least don't drop development on the JSR. As many, I consider this a great tool for UI development and expected to live within the Swing ecosystem, and not only on JavaFX. Many of us developers may just want to stick with Swing for a number of reasons (time, code reusage, tools, whatever), at least for the moment. 

Please Sun, one step forward! :) 

 

Peter Levart replied on Mon, 2009/01/19 - 5:21pm in response to: Miguel Garcia-lopez

[quote]I assume by sharing your code here I may be able to adapt it for my project, may you please confirm? No problem granting you any mention or whatever within. [/quote]

 Of course. Go ahead. Use it as you feel fit. I release it to the public.

Peter

Mateo Gomez replied on Fri, 2012/08/03 - 2:12am in response to: Peter Levart

thanks for sharing,..indeed the public needs this

mexican salsa recipes

Matt Coleman replied on Thu, 2013/03/14 - 1:09am

thank you for this...i appreciate it!

buffalo search engine optimization 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.