Beans Binding Via The Road Less Travelled By (Part 1)

At the end of my blog entry yesterday, Mark Ashworth writes: "I would just like to know if there is a demo or tutorial on how to use binding with List and JTable." Well, Mark, especially for you I've created a small yet powerful demo that relies heavily on beans binding (JSR-295). It could also have made use of the Swing Application Framework (JSR-296), but, so as not to confuse things, I've not touched that area at all here.

At the end of this blog entry, you'll have a JFrame that contains a JTable. The JTable is filled with data from a database. Whenever you select a row in the JTable, the JTextFields below the JTable are filled with the data from the currently selected row:

And no code was typed to make all of this functionality possible. However, in the explanation that follows, we will ONLY use the code editor. Nothing will be generated. And, again, I could have used a Swing Application Framework template to generate all of the above (plus a lot more, such as CRUD functionality). However, let's only look at beans binding. We'll also assume that you are NOT using the Matisse GUI Builder, either because you don't like NetBeans IDE or you don't like having your code generated or because you actually want to learn what all the code does or some other reason. So everything will be hand coded. Let's get started.

  1. First, we create the JFrame that will contain all the other Swing components:

    public class DemoJFrame extends JFrame {
    
        public DemoJFrame() {
            
            setTitle("Demo Frame");
            setSize(400,400);
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            
        }
        
        public static void main(String args[]) {
            java.awt.EventQueue.invokeLater(new Runnable() {
    
                public void run() {
                    new DemoJFrame().setVisible(true);
                }
            });
        }
    }

    Run the JFrame and you see a nice pristine space where all the action will take place.

  2. Next, you need to manually set up your database connection, which is not much fun, especially when you consider that all this can automatically be done for you. However, to set up the database, you need the following JARs on your classpath (again, these would be put there for you if you were to use the IDE's tools instead of doing it manually): beansbinding-1.2.1.jar, toplink-essentials.jar, toplink-essentials-agent.jar and derbyclient.jar. Next, you need an entity class called Customer.java, to represent the data in your database, which you can download here. Finally, for this step, you need to have a database started up and you need an XML file named "persistence.xml", in your application's META-INF folder. The content of the XML file should be as follows, assuming you're using the 'sample' database that comes with NetBeans IDE (so, you'd need to tweak it, as well as the Customer.java class, for your own purposes):

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
        <persistence-unit name="samplePU" transaction-type="RESOURCE_LOCAL">
            <provider>oracle.toplink.essentials.PersistenceProvider</provider>
            <class>demoframe.Customer</class>
            <properties>
                <property name="toplink.jdbc.user" value="app"/>
                <property name="toplink.jdbc.password" value="app"/>
                <property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
                <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
            </properties>
        </persistence-unit>
    </persistence>

  3. Now, having dealt with the formalities, let's create a JTable and bind its columns to columns in our database. Let's start by declaring some fields and variables:

    private java.util.List customerList;
    private javax.persistence.Query customerQuery;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    private javax.persistence.EntityManager samplePUEntityManager;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;

    Then, here is the actual code, which all belongs in the constructor, below the three lines we added previously. Note the pattern by which things happen: we create a binding group, we add other binding groups to it, within which we add bindings. The bindings use expression language to link to database column names, they also specify table column names and the type of the data.

    //Create new binding group:
    bindingGroup = new BindingGroup();
    
    //Persistence manager for our database:
    samplePUEntityManager = javax.persistence.Persistence.createEntityManagerFactory("samplePU").createEntityManager();
    
    //Query that we call on the persistence manager:
    customerQuery = samplePUEntityManager.createQuery("SELECT c FROM Customer c");
    
    //List that results from our query:
    customerList = customerQuery.getResultList();
    
    //JScrollPane that will contain our table:
    jScrollPane1 = new javax.swing.JScrollPane();
    
    //JTable that will contain our data:
    jTable1 = new javax.swing.JTable();
    
    //Create the JTable binding:
    JTableBinding jTableBinding = SwingBindings.createJTableBinding(
             AutoBinding.UpdateStrategy.READ_WRITE, customerList, jTable1);
    
    //Add the first column binding to our table binding:
    ColumnBinding columnBinding = jTableBinding.addColumnBinding(ELProperty.create("${name}"));
    columnBinding.setColumnName("Name");
    columnBinding.setColumnClass(String.class);
    
    //Add the second binding to our table binding:
    columnBinding = jTableBinding.addColumnBinding(ELProperty.create("${city}"));
    columnBinding.setColumnName("City");
    columnBinding.setColumnClass(String.class);
    
    //Add the final binding to our table binding:
    columnBinding = jTableBinding.addColumnBinding(ELProperty.create("${zip}"));
    columnBinding.setColumnName("Zip");
    columnBinding.setColumnClass(String.class);
    
    //Add our table binding to the binding group:
    bindingGroup.addBinding(jTableBinding);
    
    //Bind the table binding:
    jTableBinding.bind();
    
    //Set the JTable in the JScrollPane's view port view:
    jScrollPane1.setViewportView(jTable1);
    
    //Add the JScrollPane in the North:
    getContentPane().add(jScrollPane1, java.awt.BorderLayout.NORTH);
    
    //Bind the whole group:
    bindingGroup.bind();
    
    //Pack:
    pack();

    If you run the above, assuming you've actually gone through the pain of setting up the database manually, you'll see the columns in the database bound to the columns in the table. Now experiment a bit! For example, change the expression ${city} to ${email} which, if you look in your Customer.java class, maps to the "email" column in the table. Then run the application again and the City column is filled with e-mail data.

  4. Now we'll add our JTextFields. These we will bind to the columns in the table so that, whenever a row is selected, the fields will be filled with the data from the selected row.

    First, declare the new Swing components that we will work with:

    private javax.swing.JTextField jTextField1;
    private javax.swing.JTextField jTextField2;
    private javax.swing.JTextField jTextField3;
    private javax.swing.JPanel jPanel1;

    Next, below the line that adds the JScrollPane to the South, add all the following code, simply for adding a JPanel with our three JTextFields:

    jTextField1 = new javax.swing.JTextField();
    jTextField2 = new javax.swing.JTextField();
    jTextField3 = new javax.swing.JTextField();
    jPanel1 = new javax.swing.JPanel();
    
    jTextField1.setText("");
    jTextField1.setColumns(10);
    jPanel1.add(jTextField1);
    
    jTextField2.setText("");
    jTextField2.setColumns(10);
    jPanel1.add(jTextField2);
    
    jTextField3.setText("");
    jTextField3.setColumns(10);
    jPanel1.add(jTextField3);
    
    getContentPane().add(jPanel1, java.awt.BorderLayout.SOUTH);

  5. And, finally, we add the bindings. These will bind our JTextFields to columns in the table. The additions to the code I have marked in bold below:

    jTextField1.setText("");
    jTextField3.setEditable(false);
    jTextField1.setColumns(10);
    Binding binding1 = Bindings.createAutoBinding(
            AutoBinding.UpdateStrategy.READ_WRITE, 
            jTable1, 
            ELProperty.create("${selectedElement.name}"), 
            jTextField1,
            BeanProperty.create("text"));
    bindingGroup.addBinding(binding1);
    jPanel1.add(jTextField1);
    
    jTextField2.setText("");
    jTextField3.setEditable(false);
    jTextField2.setColumns(10);
    Binding binding2 = Bindings.createAutoBinding(
            AutoBinding.UpdateStrategy.READ_WRITE, 
            jTable1, 
            ELProperty.create("${selectedElement.city}"), 
            jTextField2,
            BeanProperty.create("text"));
    bindingGroup.addBinding(binding2);
    jPanel1.add(jTextField2);
    
    jTextField3.setText("");
    jTextField3.setEditable(false);
    jTextField3.setColumns(10);
    Binding binding3 = Bindings.createAutoBinding(
            AutoBinding.UpdateStrategy.READ_WRITE, 
            jTable1, 
            ELProperty.create("${selectedElement.zip}"), 
            jTextField3, 
            BeanProperty.create("text"));
    bindingGroup.addBinding(binding3);
    jPanel1.add(jTextField3);

    For what it's worth, here's a full list of my import statements:

    import javax.swing.JFrame;
    import org.jdesktop.beansbinding.AutoBinding;
    import org.jdesktop.beansbinding.BeanProperty;
    import org.jdesktop.beansbinding.Binding;
    import org.jdesktop.beansbinding.BindingGroup;
    import org.jdesktop.beansbinding.Bindings;
    import org.jdesktop.beansbinding.ELProperty;
    import org.jdesktop.swingbinding.JTableBinding;
    import org.jdesktop.swingbinding.JTableBinding.ColumnBinding;
    import org.jdesktop.swingbinding.SwingBindings;

I know I haven't explained everything in detail. I'll do that another time (once I know what those details are). On top of that, though, I think the code is relatively easy to read. You should be able to figure out what is happening, in most cases. And remember: every single piece of code that you see above, every line, every JAR, everything, is generated for you in the IDE. You do not need to go through any of this at all. Unless, of course, you want to really understand beans binding!

Comments:

Here is another request. What is the best way of approaching a Netbeans RCP application which reads data off a JMS Bus, TCP/IP connection, etc., and populates a JTable (or whatever netbeans uses)?

I would like to try building a small stock trading application using Netbeans, which requires LOTS of streaming data, binding, etc. Do I introduce the streaming data sources as some sort of services or plug-ins?

Posted by falcon on February 11, 2008 at 12:04 PM PST #

That question has nothing to do with this blog entry and I don't know the answer. Please write to dev@openide.netbeans.org and someone there will probably have implemented something similar.

Posted by Geertjan on February 11, 2008 at 03:15 PM PST #

jTableBinding.bind();
...
bindingGroup.bind();

Is this really needed? Why I must order 2 bindings if the tableBinding was asigned to the groupBinding?

Posted by peregrino on February 17, 2008 at 05:15 PM PST #

How do you make the column bindings using Netbeans IDE only? If I look at the properties, bindings of a table I can only bind things like elements or selectedElement(s)? The columns tab also doesn't appear to contain anything to do with bindings?

Could the same technique be used with the swinglabs JXTable implementation?

Posted by Richard Osbaldeston on February 18, 2008 at 07:40 PM PST #

Oh think I've found the limits myself. I was being blocked by a "can't import data to the default package" message. So you can only bind columns to a database table? I'm using RMI (raw objects/pojos) guess the existing Netbeans editor can't help here?

Posted by Richard Osbaldeston on February 18, 2008 at 07:48 PM PST #

2Richard, from what I have understood at SwingX forums, yes, you should be able to bind to JXTable too.

Also, I would be interested in replies to Richard Osbaldeston's questions regarding binding POJOs in NB. I managed to do that "manually" but not in NB binding editor.

Related to POJOs is my question - did anyone got working create and delete from underlying table model, i.e. DefaultTableModel or class extending that. If so, how? The binding does not seem to listen on table model events...

Posted by Dale Cooper on February 19, 2008 at 09:23 AM PST #

I wrote something for NetBeans Zone today that attempts to answer some of the questions here. If it doesn't feel free to leave questions at the end of that article:

http://netbeans.dzone.com/news/binding-jtable-swing-controls-

Posted by Geertjan on February 19, 2008 at 04:39 PM PST #

Hi!

Thanks for your tutorial!

I did the same within a Netbeans RCP App, but when i write text into one of my TextFields, the corresponding Table Column doesn't get updated.

When i do the same outside Netbeans RCP Platform everything works perfect....

Whats wrong within Netbeans RCP?

Best Regards,
christian

Posted by Christian on April 09, 2008 at 07:50 PM PDT #

Has you tried this to work with EclipseLink JPA, resource local, i.e. the javax.persistence_1.0.0.jar?

Can you suggest a site that shows how to migrate toplink-essentials 1.0 to eclipselink?

By the way, this is a really informative example ... Some of us are using Java SE with JPA, and not just for testing.

Posted by Mike Rainville on August 12, 2008 at 08:48 AM PDT #

this might have been useful if the 3 examples had been for string int and boolean instead of all being for string

Posted by tom ballard on March 29, 2010 at 07:32 AM PDT #

Thanks very much for your tutorial.

Are there any NetBeans 6.9 Java DB tutorials which show add/update/delete functionality to a jTable that was not generated by master/detail -it is a single table with some data.

-Thanks
Lana

Posted by Lana on August 10, 2010 at 06:09 AM PDT #

Hellos Sir, how can bind jpanel in netbeans to load contents from a class after a button get pressed?
let me make my self clear, I want to put a textfield to search data with a button and in the bottom i'll put a jpanel to show the content. Thank you

Posted by veronel on October 02, 2010 at 04:08 PM PDT #

Hello Geertjan,

I've let NB create all of the binding as you've suggested. jTable bound to a db (MySQL), and various form fields (jTextField's) manually bound (through IDE, bind-text, etc.) to said jTable. Clicking jTable fills textfields. So far, so good. I've also added custom handlers to populate other parts of the form based on, fired with jTable selection.

This all works great.

However, the one thing I can't seem to figure out is... how to manually update the jTable when the DB is updated. (And I don't seem to be alone in this quandary, as MANY have googled...)

When clicking save, I manually do a DB update/insert from the form fields, which works, but need to refresh the jTable to show the new data.

I've looked for several days for some clue as to how to tell the PUEntity to do this but have found no real answer. I think* it must be done with some sort of TableModel method but can't seem to figure it out

I know this is an old post but I am stuck in the middle of a project and have spent days looking for any kind of help with this and you obviously seem to know what you're talking about here.

Thanks in advance,
A Nother Starving Programmer

Posted by guest on July 25, 2011 at 02:45 PM PDT #

Hi,

I would like to know how can i change the data in the JTable when I make a new query and have a new customerList (after an insert in the Customers table for example)?

Thanks a lot,

Posted by guest on October 25, 2011 at 11:57 PM PDT #

Hi, I'm having problems saving data from a jlabel and jcombobox (directly bound to the entity class).

Please show me a working example of CRUD type netbeans app like the above code that doesn't use a jtable because I'm lost

thanks

Posted by Lesanjo on January 22, 2012 at 06:34 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
19
21
22
23
24
25
26
27
28
29
30
   
       
Today