X

Geertjan's Blog

  • February 11, 2008

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

Geertjan Wielenga
Product Manager
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!

Join the discussion

Comments ( 15 )
  • falcon Monday, February 11, 2008

    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?


  • Geertjan Monday, February 11, 2008

    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.


  • peregrino Monday, February 18, 2008

    jTableBinding.bind();

    ...

    bindingGroup.bind();

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


  • Richard Osbaldeston Tuesday, February 19, 2008

    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?


  • Richard Osbaldeston Tuesday, February 19, 2008

    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?


  • Dale Cooper Tuesday, February 19, 2008

    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...


  • Geertjan Wednesday, February 20, 2008

    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-


  • Christian Thursday, April 10, 2008

    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


  • Mike Rainville Tuesday, August 12, 2008

    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.


  • tom ballard Monday, March 29, 2010

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


  • Lana Tuesday, August 10, 2010

    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


  • veronel Saturday, October 2, 2010

    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


  • guest Monday, July 25, 2011

    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


  • guest Wednesday, October 26, 2011

    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,


  • Lesanjo Sunday, January 22, 2012

    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


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.