NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed. (sponsored)
In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.
Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.
Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Welcome back tip readers. I'm hoping all of you are ready to read more about the JGoodies binding framework. If you missed my last tip, too bad. Just kidding - you can find it
here - JGoodies: Understanding Binding - Part 1
. Yesterday I briefly ran through the subject of JGoodies binding, with the hope I could show you enough to whet your appetite, but I didn't show a whole lot about the usage - I pretty much showed how to bind a text field and a checkbox, and that was it. There is so much more, however.
A Little More Detail
So you are feeling a lack of control because right now you can only use checkboxes and text fields? It seems to me it is surely possible to build an entire application out of just those. Surely you don't expect to be able to use sliders, radio buttons, lists and combo boxes - that'd just be greedy. While I suppose that would be an interesting study (building an application composed entirely of two component types), it doesn't sound very user friendly.
One of the things I always want to avoid with my tips is being to wordy. Let's face it - it's hard for me; I obviously can find more than enough to say about a subject, and manage to often do so incoherently on top of that. Thankfully, the binding framework speaks volumes just by being implemented and used as I did in the previous tip. The fact is, the transparency it provides is so apparent (isn't that an oxy-moron - 'apparent transparency'?) that it is hard not to understand the value it can provide. In that sense, this tip should be a good one, as I plan to mostly use code examples to get through the real world examples of the different bindings that it can perform.
Beyond a Trivial Example
Yesterday's tip was, unfortunately, a little trivial. I covered binding a couple simple bean properties to a few view components - but when you get into real world applications, that just doesn't cut the metaphorical mustard. So what I want to do now is cover other components in either a cursory glance, or if the situation merits, some more detailed examples to show the different patterns of usage. Also, I will commonly be using the BasicComponentFactory and other similar classes in this example. I will NOT be exercising all possible methods available - many of these methods/constructors take many variations of the parameters I pass - so do some digging. The best way to do that digging is to look at the API documentation for each adapter for view elements - and while I'm at it, before I move forward, a comprehensive list of adaptations for view elements can be found in /docs/guide/viewadapters.html in your downloaded binding framework folder... what do you mean you didn't download the binding framework yet?
GO GET IT!
.
Many of the bindable components can be approached in the exact same way as our textfield and checkbox from yesterday. For instance, JToggleButton and JCheckBoxMenuItem are handled exactly the same as JCheckBox elements. Likewise, JTextArea and JPasswordField are handled exactly the same as JTextField. Because of that, I don't see it being worth my time or yours to detail how to create/bind them here - shouldn't be too hard to get from A->B if you catch my drift. There are some wierd cases however, so keep reading.
Binding a Radio Button to a Field
Ok - wierd item one - radio buttons. Radio buttons turn out to be quite easy to bind. Multiple radio buttons in the same button group are assigned to a single value model, but each one is given a unique value to set on the bean property when selected. Ok sorry, again there I go with the words. Here is a code example that uses our existing
MyBean.java
class, and provides two choices for a value on the
stringValue
field (note, the exact same is possible for JRadioButtonMenuItem elements):
publicclass Binding {
publicstaticvoid main(String[] args) {
MyBean bean = new MyBean();
// Bean adapter is an adapter that can create many value model objects for a single
// bean. It is more efficient than the property adapter. The 'true' once again means
// we want it to observe our bean for changes.
BeanAdapter adapter = new BeanAdapter(bean, true);
// set the string value to one of the radio button's associated values
bean.setStringValue("value1");
ValueModel booleanModel = adapter.getValueModel("booleanValue");
ValueModel stringModel = adapter.getValueModel("stringValue");
// creates a JCheckBox with the property adapter providing the underlying model.
JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value");
// create two radio buttons... 1st one binds 'value1' to 'stringValue'
// 2nd one binds 'value2'.
JRadioButton button1 = BasicComponentFactory.createRadioButton(stringModel, "value1", "Value 1");
JRadioButton button2 = BasicComponentFactory.createRadioButton(stringModel, "value2", "Value 2");
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new GridLayout(2,1));
frame.getContentPane().add(box);
frame.getContentPane().add(button1);
frame.getContentPane().add(button2);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Pretty easy, right? I'm impressed with the simplicity of this setup, and I'm also impressed that all is required to ensure that a radio button is selected from the group at initialization is simply setting that radio button's value on the bean itself (note this will also work once the components are actually bound together).
Binding a Bounded Slider to a Field
Woah, wait a minute. Sliders have always been a pain in the tropal tailbone to interact with effectively in Java. Not anymore. While for whatever reason the
BasicComponentFactory
and
Bindings
factories don't seem to have entries for the slider, all that is required is using a
BoundedRangeAdapter
object as the
BoundedRangeModel
on the slider, and setting it up for our bean's value model. Here is an example that sets up a slider with allowed values between 0 and 500.
Notice in this example I dropped our
booleanValue
on the
MyBean
bean in favor of an
intValue
(as integers work just a *little* bit better with sliders).
// MyBean.java
import java.beans.PropertyChangeListener;
import com.jgoodies.binding.beans.*;
publicclass MyBean {
// Note you don't HAVE to use this class - you can use
// java.beans.PropertyChangeSupport if you want.
private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport(
this);
privateint intValue;
private String stringValue;
publicint getIntValue() {
return intValue;
}
publicvoid setIntValue(int newValue) {
System.out.println("Boolean value set: " +newValue);
int oldValue = intValue;
intValue = newValue;
changeSupport.firePropertyChange("intValue", oldValue, newValue);
}
publicvoid addPropertyChangeListener(PropertyChangeListener x) {
changeSupport.addPropertyChangeListener(x);
}
publicvoid removePropertyChangeListener(PropertyChangeListener x) {
changeSupport.removePropertyChangeListener(x);
}
public String getStringValue() {
return stringValue;
}
publicvoid setStringValue(String newValue) {
System.out.println("String value set: "+ newValue);
String oldValue = stringValue;
this.stringValue = newValue;
changeSupport.firePropertyChange("stringValue", oldValue, newValue);
}
}
// Binding.java
import java.awt.GridLayout;
import javax.swing.*;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.adapter.BoundedRangeAdapter;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.value.ValueModel;
publicclass Binding {
publicstaticvoid main(String[] args) {
MyBean bean = new MyBean();
// Bean adapter is an adapter that can create many value model objects for a single
// bean. It is more efficient than the property adapter. The 'true' once again means
// we want it to observe our bean for changes.
BeanAdapter adapter = new BeanAdapter(bean, true);
ValueModel intModel = adapter.getValueModel("intValue");
ValueModel stringModel = adapter.getValueModel("stringValue");
// creates a slider and a new bounded range adapter.
// the range adapter is given our integer value model, and a range of 0-500.
JSlider slider = new JSlider(new BoundedRangeAdapter(intModel, 0, 0, 500));
JRadioButton button1 = BasicComponentFactory.createRadioButton(stringModel, "value1", "Value 1");
JRadioButton button2 = BasicComponentFactory.createRadioButton(stringModel, "value2", "Value 2");
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new GridLayout(2,1));
frame.getContentPane().add(slider);
frame.getContentPane().add(button1);
frame.getContentPane().add(button2);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Once again, a walk in the park.
Ok, so what about the less conventional widgets. What do I mean by conventional? Well, two widgets that for one reason or another don't implement an underlying model are the
JLabel
and the
JFormattedTextField
. What do we do if there is no model to adapt? Well, this is where we introduce the
Property Connector
.
Property Connectors
Property connectors are an interesting tool. The most common usage in the binding framework is for connecting non-modeled widgets to bean properties. Interestingly enough, however, it can be used more generally - simply to connect and synchronize multiple beans. Before I get ahead of myself though, let me explain what a property connector is. Property connectors differ from property adapters because they use the word connector instead of the word adapter. Ok, I can feel you pulling away from the hideousness of that joke. Seriously though, instead of connecting a widget's model to a bean, property connectors simply connect two bean properties. Thankfully, since most Swing elements follow (to at least some extent) the Javabean specification, any of the widgets that don't have a model, can be connected by using property connectors. This includes the
setText
on a JLabel and JFormattedTextField. Be aware, however, that PropertyConnectors make no attempt to convert types from one bean to another. That means that if you are using a JFormattedTextFields for dates, it better be bound to a field of
java.util.Date
type (and labels better be strings). Here is how a label is bound:
Now you may be saying, "But JLabels aren't editable - binding them to a bean is a waste of time", and you'd be right. Just kidding - don't forget that these bindings are
BI
-directional. While the user can't edit the JLabel - some other behavior in the application (such as changing a JTextField) may have updated the bean. Because the JLabel is bound to the bean, it will automagically be updated! JFormattedTextFields are created in much the same way - re-listing the entire contents of the bean and the binding test would largely be repetitive here; just remember that the fields must be of the correct type!
Lists of Stuff
A-ha! I know what the binding framework doesn't support.
JList
s and
JComboBox
s. Well, no, actually it does. To start, here is how you can bind our existing
MyBean
instance to a single-selection JList (yes, I'm using the same old worn out bean, once again):
Note that while in the above example, I provide the possible values explicitly, it is just as possible to get them directly from the bean (as another value model backed by a
java.util.List
). As best as I can tell, there is (as of yet) no way to automatically bind a mulitple-selection list to a bean. I may be wrong about this, so don't take my word as gold, but short of implementing my own adapter (hah!), I haven't found any way to have a fully supported mulitple-select list. Incidentally, the class that performs adaptation of the selections is the
com.jgoodies.binding.adapter.SingleListSelectionAdapter
.
Combo boxes can be handled in a similar way to single-selection lists, although it can be a little less complicated (given the right constructor usage):
Whew! Well, I'm about beat for this session of JGoodies Bindings. I hope you learned a little about binding various 'real world' widgets to your beans. Don't go scurrying off yet, however. Next on the agenda is to spend more time understanding the more advanced benefits that can be found by using the value model intermediaries. To do some name dropping, this includes usage of the
PresentationModel
class, the
BufferedValueModel
,
Triggers
and a few others. Finally, two tips from now I want to finish out my look at the binding framework by discussing some helpful classes that ship with it, but aren't neccessarily directly needed. If time merits, I'll also discuss some of the extras, and if I'm feeling really persistent I'll also discuss the super-ultra-top-secret-advanced features.
This looks like a very cool framework. Ever since I started working with Tapestry and Hibernate (two frameworks that provide data mapping) I've wondered why we didn't have something like this for Swing. Glad to see it's out there.
I might try adapting an existing app I have to this. If I do I'll post my results. Need to see how it handles JFormattedTextFields though, have a ton of those.
Pretty cool!
I am using the framework on a swing application I started
building and it seems very helpful, however I cannot find in the article a good description of the behaviour of the PropertyConnectors.
In the example it is not really explained how to use them, while they are clearly useful in all the situations where custom components are used. In my case I developed a TextBox that holds a Double value and I wanted to bind it to a Double property but I couldn't manage to get it to work with the usual PropertyAdapter I guess because the getValue of my control retruns a Double instead of a String.
If you wanted to, you can then glue those two beans properties (valueA, valueB) together (notice there is no Swing code here) by using a property connector:
BeanA beanA = new BeanA();
BeanB beanB = new BeanB();
PropertyConnector.connect(beanA, "valueA", beanB, "valueB");
beanA.setValueA("blah"); // sets valueA, and then triggers a set on beanB
System.out.println(beanB.getValueB()); // prints 'blah'
beanB.setValueB("kaboom"); // sets valueB, and then triggers a set on beanA
System.out.println(beanA.getValueA()); // prints 'kaboom'
With regard to your 'textbox' - should I assume this custom connector simply extends JComponent? Or does it extend JTextComponent, or something more specific? Understanding that will bring me a lot closer to understanding what problem you are having.
Thank you very much for the tips.
My textbox is used to limit the user input to floating point numbers with a given number of decimal places and
values falling within a given interval. It extends JTextbox and has a custom Document that extends PlainDocument to perform checks on the input while the user is typing. The document has a value property of type Double. I am not assuming this is the most elegant solution to the problem but It is the best I could think of at the moment.
What I did in order to bind the document value was to:
1) Add a PropertyChangeSupport to the document class:
private PropertyChangeSupport changeSupport = new PopertyChangeSupport(this)
2) Add the two methods to add and remove PropertyChangeListeners:
public void addPropertyChangeListener(PropertyChangeListener x) {
changeSupport.addPropertyChangeListener(x);
}
public void removePropertyChangeListener(PropertyChangeListener x) {
changeSupport.removePropertyChangeListener(x);
}
3) fire the the PropertyChangeEvent within the setValue(Double newValue) method:
changeSupport.firePropertyChange("value",OldValue,newValue);
Similarly to the examples, I added in the main method of the test class a PropertyConnector to bind the document to a Double field in domain class bean:
PropertyConnector connector =
new PropertyConnector(doubleTextBox.getDocument(), "value",doubleModel, "value");
where doubleModel is the valueModel conneted to the bean.
BeanAdapter adapter = new BeanAdapter(bean, true);
ValueModel doubleModel = adapter.getValueModel("doubleValue");
I didn't get the thing working at the beginning because I mistakenly assigned the OldValue parameter in the firePropertyChange of the setValue method of the document class to the newValue so that the actual method call was:
With Strandz you use a class called 'Attribute' to do the binding. There is also a Designer available which takes all the work out of the mapping of screen items to data object fields. And the concepts go a little further than just mapping - there are 'master detail' and 'lookup' as well. Once you've done all the mapping work these two concepts put it all into productive action.
JGoodies: Understanding Binding - Part 2
At 1:14 AM on Mar 10, 2005, R.J. Lorimer wrote:
Fresh Jobs for Developers Post a job opportunity
Welcome back tip readers. I'm hoping all of you are ready to read more about the JGoodies binding framework. If you missed my last tip, too bad. Just kidding - you can find it here - JGoodies: Understanding Binding - Part 1 . Yesterday I briefly ran through the subject of JGoodies binding, with the hope I could show you enough to whet your appetite, but I didn't show a whole lot about the usage - I pretty much showed how to bind a text field and a checkbox, and that was it. There is so much more, however.
A Little More Detail
So you are feeling a lack of control because right now you can only use checkboxes and text fields? It seems to me it is surely possible to build an entire application out of just those. Surely you don't expect to be able to use sliders, radio buttons, lists and combo boxes - that'd just be greedy. While I suppose that would be an interesting study (building an application composed entirely of two component types), it doesn't sound very user friendly.
One of the things I always want to avoid with my tips is being to wordy. Let's face it - it's hard for me; I obviously can find more than enough to say about a subject, and manage to often do so incoherently on top of that. Thankfully, the binding framework speaks volumes just by being implemented and used as I did in the previous tip. The fact is, the transparency it provides is so apparent (isn't that an oxy-moron - 'apparent transparency'?) that it is hard not to understand the value it can provide. In that sense, this tip should be a good one, as I plan to mostly use code examples to get through the real world examples of the different bindings that it can perform.
Beyond a Trivial Example
Yesterday's tip was, unfortunately, a little trivial. I covered binding a couple simple bean properties to a few view components - but when you get into real world applications, that just doesn't cut the metaphorical mustard. So what I want to do now is cover other components in either a cursory glance, or if the situation merits, some more detailed examples to show the different patterns of usage. Also, I will commonly be using the BasicComponentFactory and other similar classes in this example. I will NOT be exercising all possible methods available - many of these methods/constructors take many variations of the parameters I pass - so do some digging. The best way to do that digging is to look at the API documentation for each adapter for view elements - and while I'm at it, before I move forward, a comprehensive list of adaptations for view elements can be found in /docs/guide/viewadapters.html in your downloaded binding framework folder... what do you mean you didn't download the binding framework yet? GO GET IT! .
Many of the bindable components can be approached in the exact same way as our textfield and checkbox from yesterday. For instance, JToggleButton and JCheckBoxMenuItem are handled exactly the same as JCheckBox elements. Likewise, JTextArea and JPasswordField are handled exactly the same as JTextField. Because of that, I don't see it being worth my time or yours to detail how to create/bind them here - shouldn't be too hard to get from A->B if you catch my drift. There are some wierd cases however, so keep reading.
Binding a Radio Button to a Field
Ok - wierd item one - radio buttons. Radio buttons turn out to be quite easy to bind. Multiple radio buttons in the same button group are assigned to a single value model, but each one is given a unique value to set on the bean property when selected. Ok sorry, again there I go with the words. Here is a code example that uses our existing
MyBean.javaclass, and provides two choices for a value on thestringValuefield (note, the exact same is possible for JRadioButtonMenuItem elements):public class Binding { public static void main(String[] args) { MyBean bean = new MyBean(); // Bean adapter is an adapter that can create many value model objects for a single // bean. It is more efficient than the property adapter. The 'true' once again means // we want it to observe our bean for changes. BeanAdapter adapter = new BeanAdapter(bean, true); // set the string value to one of the radio button's associated values bean.setStringValue("value1"); ValueModel booleanModel = adapter.getValueModel("booleanValue"); ValueModel stringModel = adapter.getValueModel("stringValue"); // creates a JCheckBox with the property adapter providing the underlying model. JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value"); // create two radio buttons... 1st one binds 'value1' to 'stringValue' // 2nd one binds 'value2'. JRadioButton button1 = BasicComponentFactory.createRadioButton(stringModel, "value1", "Value 1"); JRadioButton button2 = BasicComponentFactory.createRadioButton(stringModel, "value2", "Value 2"); JFrame frame = new JFrame(); frame.getContentPane().setLayout(new GridLayout(2,1)); frame.getContentPane().add(box); frame.getContentPane().add(button1); frame.getContentPane().add(button2); frame.pack(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } }Pretty easy, right? I'm impressed with the simplicity of this setup, and I'm also impressed that all is required to ensure that a radio button is selected from the group at initialization is simply setting that radio button's value on the bean itself (note this will also work once the components are actually bound together).
Binding a Bounded Slider to a Field
Woah, wait a minute. Sliders have always been a pain in the tropal tailbone to interact with effectively in Java. Not anymore. While for whatever reason the
BasicComponentFactoryandBindingsfactories don't seem to have entries for the slider, all that is required is using aBoundedRangeAdapterobject as theBoundedRangeModelon the slider, and setting it up for our bean's value model. Here is an example that sets up a slider with allowed values between 0 and 500. Notice in this example I dropped ourbooleanValueon theMyBeanbean in favor of anintValue(as integers work just a *little* bit better with sliders).// MyBean.java import java.beans.PropertyChangeListener; import com.jgoodies.binding.beans.*; public class MyBean { // Note you don't HAVE to use this class - you can use // java.beans.PropertyChangeSupport if you want. private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport( this); private int intValue; private String stringValue; public int getIntValue() { return intValue; } public void setIntValue(int newValue) { System.out.println("Boolean value set: " +newValue); int oldValue = intValue; intValue = newValue; changeSupport.firePropertyChange("intValue", oldValue, newValue); } public void addPropertyChangeListener(PropertyChangeListener x) { changeSupport.addPropertyChangeListener(x); } public void removePropertyChangeListener(PropertyChangeListener x) { changeSupport.removePropertyChangeListener(x); } public String getStringValue() { return stringValue; } public void setStringValue(String newValue) { System.out.println("String value set: "+ newValue); String oldValue = stringValue; this.stringValue = newValue; changeSupport.firePropertyChange("stringValue", oldValue, newValue); } } // Binding.java import java.awt.GridLayout; import javax.swing.*; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.adapter.BoundedRangeAdapter; import com.jgoodies.binding.beans.BeanAdapter; import com.jgoodies.binding.value.ValueModel; public class Binding { public static void main(String[] args) { MyBean bean = new MyBean(); // Bean adapter is an adapter that can create many value model objects for a single // bean. It is more efficient than the property adapter. The 'true' once again means // we want it to observe our bean for changes. BeanAdapter adapter = new BeanAdapter(bean, true); ValueModel intModel = adapter.getValueModel("intValue"); ValueModel stringModel = adapter.getValueModel("stringValue"); // creates a slider and a new bounded range adapter. // the range adapter is given our integer value model, and a range of 0-500. JSlider slider = new JSlider(new BoundedRangeAdapter(intModel, 0, 0, 500)); JRadioButton button1 = BasicComponentFactory.createRadioButton(stringModel, "value1", "Value 1"); JRadioButton button2 = BasicComponentFactory.createRadioButton(stringModel, "value2", "Value 2"); JFrame frame = new JFrame(); frame.getContentPane().setLayout(new GridLayout(2,1)); frame.getContentPane().add(slider); frame.getContentPane().add(button1); frame.getContentPane().add(button2); frame.pack(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } }Once again, a walk in the park.
Ok, so what about the less conventional widgets. What do I mean by conventional? Well, two widgets that for one reason or another don't implement an underlying model are the
JLabeland theJFormattedTextField. What do we do if there is no model to adapt? Well, this is where we introduce theProperty Connector.Property Connectors
Property connectors are an interesting tool. The most common usage in the binding framework is for connecting non-modeled widgets to bean properties. Interestingly enough, however, it can be used more generally - simply to connect and synchronize multiple beans. Before I get ahead of myself though, let me explain what a property connector is. Property connectors differ from property adapters because they use the word connector instead of the word adapter. Ok, I can feel you pulling away from the hideousness of that joke. Seriously though, instead of connecting a widget's model to a bean, property connectors simply connect two bean properties. Thankfully, since most Swing elements follow (to at least some extent) the Javabean specification, any of the widgets that don't have a model, can be connected by using property connectors. This includes the
setTexton a JLabel and JFormattedTextField. Be aware, however, that PropertyConnectors make no attempt to convert types from one bean to another. That means that if you are using a JFormattedTextFields for dates, it better be bound to a field ofjava.util.Datetype (and labels better be strings). Here is how a label is bound:import java.awt.GridLayout; import javax.swing.*; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.adapter.Bindings; import com.jgoodies.binding.adapter.BoundedRangeAdapter; import com.jgoodies.binding.beans.BeanAdapter; import com.jgoodies.binding.value.ValueModel; public class Binding { public static void main(String[] args) { MyBean bean = new MyBean(); BeanAdapter adapter = new BeanAdapter(bean, true); ValueModel stringModel = adapter.getValueModel("stringValue"); JLabel label = BasicComponentFactory.createLabel(stringModel); JFrame frame = new JFrame(); frame.getContentPane().setLayout(new GridLayout(2,1)); frame.getContentPane().add(label); frame.pack(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } }Now you may be saying, "But JLabels aren't editable - binding them to a bean is a waste of time", and you'd be right. Just kidding - don't forget that these bindings are BI -directional. While the user can't edit the JLabel - some other behavior in the application (such as changing a JTextField) may have updated the bean. Because the JLabel is bound to the bean, it will automagically be updated! JFormattedTextFields are created in much the same way - re-listing the entire contents of the bean and the binding test would largely be repetitive here; just remember that the fields must be of the correct type!
Lists of Stuff
A-ha! I know what the binding framework doesn't support.
JLists andJComboBoxs. Well, no, actually it does. To start, here is how you can bind our existingMyBeaninstance to a single-selection JList (yes, I'm using the same old worn out bean, once again):import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; import javax.swing.*; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.adapter.Bindings; import com.jgoodies.binding.adapter.BoundedRangeAdapter; import com.jgoodies.binding.beans.BeanAdapter; import com.jgoodies.binding.list.SelectionInList; import com.jgoodies.binding.value.ValueModel; public class Binding { public static void main(String[] args) { MyBean bean = new MyBean(); BeanAdapter adapter = new BeanAdapter(bean, true); ValueModel intModel = adapter.getValueModel("intValue"); ValueModel stringModel = adapter.getValueModel("stringValue"); List possibleValues = new ArrayList(); possibleValues.add("First Value"); possibleValues.add("Second Value"); possibleValues.add("Third Value"); JList jlist = BasicComponentFactory.createList(new SelectionInList(possibleValues, stringModel, intModel)); JFrame frame = new JFrame(); frame.getContentPane().setLayout(new GridLayout(2,1)); frame.getContentPane().add(jlist); frame.pack(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } }Note that while in the above example, I provide the possible values explicitly, it is just as possible to get them directly from the bean (as another value model backed by a
java.util.List). As best as I can tell, there is (as of yet) no way to automatically bind a mulitple-selection list to a bean. I may be wrong about this, so don't take my word as gold, but short of implementing my own adapter (hah!), I haven't found any way to have a fully supported mulitple-select list. Incidentally, the class that performs adaptation of the selections is thecom.jgoodies.binding.adapter.SingleListSelectionAdapter.Combo boxes can be handled in a similar way to single-selection lists, although it can be a little less complicated (given the right constructor usage):
import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; import javax.swing.*; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.adapter.Bindings; import com.jgoodies.binding.adapter.BoundedRangeAdapter; import com.jgoodies.binding.adapter.ComboBoxAdapter; import com.jgoodies.binding.beans.BeanAdapter; import com.jgoodies.binding.list.SelectionInList; import com.jgoodies.binding.value.ValueModel; public class Binding { public static void main(String[] args) { MyBean bean = new MyBean(); BeanAdapter adapter = new BeanAdapter(bean, true); ValueModel intModel = adapter.getValueModel("intValue"); ValueModel stringModel = adapter.getValueModel("stringValue"); List possibleValues = new ArrayList(); possibleValues.add("First Value"); possibleValues.add("Second Value"); possibleValues.add("Third Value"); JComboBox comboBox = new JComboBox(new ComboBoxAdapter(possibleValues, stringModel)); JFrame frame = new JFrame(); frame.getContentPane().setLayout(new GridLayout(2,1)); frame.getContentPane().add(comboBox); frame.pack(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } }Whew! Well, I'm about beat for this session of JGoodies Bindings. I hope you learned a little about binding various 'real world' widgets to your beans. Don't go scurrying off yet, however. Next on the agenda is to spend more time understanding the more advanced benefits that can be found by using the value model intermediaries. To do some name dropping, this includes usage of the
PresentationModelclass, theBufferedValueModel,Triggersand a few others. Finally, two tips from now I want to finish out my look at the binding framework by discussing some helpful classes that ship with it, but aren't neccessarily directly needed. If time merits, I'll also discuss some of the extras, and if I'm feeling really persistent I'll also discuss the super-ultra-top-secret-advanced features.Until next time,
R.J. Lorimer
rj -at- javalobby.org
http://www.coffee-bytes.com
6 replies so far (
Post your own)
Re: JGoodies: Understanding Binding - Part 2
This looks like a very cool framework. Ever since I started working with Tapestry and Hibernate (two frameworks that provide data mapping) I've wondered why we didn't have something like this for Swing. Glad to see it's out there.I might try adapting an existing app I have to this. If I do I'll post my results. Need to see how it handles JFormattedTextFields though, have a ton of those.
Keep up the good work.
Re: JGoodies: Understanding Binding - Part 2
Pretty cool!I am using the framework on a swing application I started
building and it seems very helpful, however I cannot find in the article a good description of the behaviour of the PropertyConnectors.
In the example it is not really explained how to use them, while they are clearly useful in all the situations where custom components are used. In my case I developed a TextBox that holds a Double value and I wanted to bind it to a Double property but I couldn't manage to get it to work with the usual PropertyAdapter I guess because the getValue of my control retruns a Double instead of a String.
Re: JGoodies: Understanding Binding - Part 2
Luca,PropertyConnectors for binding are useful when you have no Swing model to stand on.
In general, property connectors are useful for glue-ing two properties together on two different beans. Let's say you have two beans like this:
public class BeanA { private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport( this); private String valueA; public void setValueA(String newValueA) { String oldValueA = valueA; valueA = newValueA; changeSupport.firePropertyChange("valueA, oldValueA, newValueA); } public String getValueA() { return valueA; } }public class BeanB { private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport( this); private String valueB; public void setValueB(String newValueB) { String oldValueB = valueB; valueB = newValueB; changeSupport.firePropertyChange("valueB", oldValueB, newValueB); } public String getValueB() { return valueB; } }If you wanted to, you can then glue those two beans properties (valueA, valueB) together (notice there is no Swing code here) by using a property connector:
BeanA beanA = new BeanA(); BeanB beanB = new BeanB(); PropertyConnector.connect(beanA, "valueA", beanB, "valueB"); beanA.setValueA("blah"); // sets valueA, and then triggers a set on beanB System.out.println(beanB.getValueB()); // prints 'blah' beanB.setValueB("kaboom"); // sets valueB, and then triggers a set on beanA System.out.println(beanA.getValueA()); // prints 'kaboom'With regard to your 'textbox' - should I assume this custom connector simply extends JComponent? Or does it extend JTextComponent, or something more specific? Understanding that will bring me a lot closer to understanding what problem you are having.
Re: JGoodies: Understanding Binding - Part 2
Thank you very much for the tips.My textbox is used to limit the user input to floating point numbers with a given number of decimal places and
values falling within a given interval. It extends JTextbox and has a custom Document that extends PlainDocument to perform checks on the input while the user is typing. The document has a value property of type Double. I am not assuming this is the most elegant solution to the problem but It is the best I could think of at the moment.
What I did in order to bind the document value was to:
1) Add a PropertyChangeSupport to the document class:
private PropertyChangeSupport changeSupport = new PopertyChangeSupport(this)
2) Add the two methods to add and remove PropertyChangeListeners:
public void addPropertyChangeListener(PropertyChangeListener x) {
changeSupport.addPropertyChangeListener(x);
}
public void removePropertyChangeListener(PropertyChangeListener x) {
changeSupport.removePropertyChangeListener(x);
}
3) fire the the PropertyChangeEvent within the setValue(Double newValue) method:
changeSupport.firePropertyChange("value",OldValue,newValue);
Similarly to the examples, I added in the main method of the test class a PropertyConnector to bind the document to a Double field in domain class bean:
PropertyConnector connector =
new PropertyConnector(doubleTextBox.getDocument(), "value",doubleModel, "value");
where doubleModel is the valueModel conneted to the bean.
BeanAdapter adapter = new BeanAdapter(bean, true);
ValueModel doubleModel = adapter.getValueModel("doubleValue");
I didn't get the thing working at the beginning because I mistakenly assigned the OldValue parameter in the firePropertyChange of the setValue method of the document class to the newValue so that the actual method call was:
changeSupport.firePropertyChange("value",newValue,newValue);
which did not cause any call to the domain class bean setter method.
Re: JGoodies: Understanding Binding - Part 2
For an alternative look at binding check out:http://www.strandz.org
With Strandz you use a class called 'Attribute' to do the binding. There is also a Designer available which takes all the work out of the mapping of screen items to data object fields. And the concepts go a little further than just mapping - there are 'master detail' and 'lookup' as well. Once you've done all the mapping work these two concepts put it all into productive action.
JGoodies: Understanding Binding - Part 2
I want to Connect JCheckBox and JComboBox throughPropertyConnector.
if JCheckBox is selected then JComboBox should be Visible
and if JCheckBox is deselected then JComboBox should be
Invisible.