The Source for Java Technology Collaboration
User: Password:



Michael Nascimento Santos

Michael Nascimento Santos's Blog

Swing made easy with genesis

Posted by mister__m on August 25, 2006 at 10:43 AM | Comments (13)

Swing was always known as a powerful, highly configurable UI toolkit. However, not much longer after it was born, it was also regarded as a slow, hard to learn, confusing, hard to program toolkit. Sun first started working on performance and Swing became faster and lighter - if you only knew how to code make a GUI with it. Designing some interfaces could take hours (or days) and since there are many ways of accomplishing (almost) the same thing in Swing, developers would usually get confused or pick the wrong road. Visual designers such as VEP and later Matisse came and made it simple to design the GUI. However, working with Swing still required understanding models, writing listeners and dealing with the many choices offered by the API.

An easier programming model was needed and then binding frameworks started to appear. genesis was born two years ago and it has been supporting GUI-toolkit independent binding for more than a year and a half now. At first, only Thinlet was supported and we were always asked about when it would support Swing. Well, since the beginning of the year a Swing binding has been implemented and now it has finally been released.

What makes the binding implemented by genesis unique is that it doesn't require you to use any "proprietary" components and it doesn't require you to code listeners (neither in the interface nor the JavaBean). So you can design your interface using Matisse, write your JavaBean class and just use a couple of annotations to bring it to life. Let's see how it works in practice. Let's say we would like to implement a login use case. We could code the UI handling JavaBean, called a form, like this :


@Form
public class LoginForm {
   private String user;
   private String password;

   public String getUser() {
      return user;
   }

   public void setUser(String user) {
      this.user = user;
   }

   public String getPassword() {
      return password;
   }

   public void setPassword(String password) {
      this.password = password;
   }

   @Action
   public void login() {
      System.out.println(user);
      System.out.println(password);
   }

   @Action
   public void clear() {
      setUser(null);
      setPassword(null);
   }
}

And bind it to a Swing UI like this:


@ViewHandler
public class LoginSwingView extends JDialog {
   public LoginSwingView() {
      super(new JFrame(), "Login");
      initComponents();

      SwingBinder binder = new SwingBinder(this, new LoginForm());
      binder.bind();
   }
   
   private void initComponents() {
      getContentPane().setLayout(new GridLayout(2, 1));

      JPanel dataPanel = new JPanel();
      dataPanel.setLayout(new GridLayout(2, 2, 5, 5));

      JLabel labelUser = new JLabel();
      labelUser.setText("User");
      dataPanel.add(labelUser);

      JTextField user = new JTextField();
      user.setName("user");
      dataPanel.add(user);

      JLabel labelPassword = new JLabel();
      labelPassword.setText("Password");
      dataPanel.add(labelPassword);

      JPasswordField password = new JPasswordField();
      password.setName("password");
      dataPanel.add(password);

      getContentPane().add(dataPanel);

      JPanel buttonPanel = new JPanel();

      JButton login = new JButton();
      login.setText("Login");
      login.setName("login");
      buttonPanel.add(login);

      JButton clear = new JButton();
      clear.setText("Clear");
      clear.setName("clear");
      buttonPanel.add(clear);

      getContentPane().add(buttonPanel);

      pack();

      setLocationRelativeTo(null);

      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }

   public static void main(String args[]) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            new LoginSwingView().setVisible(true);
         }
      });
   }
}

So, as this example shows, genesis binds JavaBeans properties to widgets such as JLabels, JTextFields and others based on their names. This is just the default behaviour; it is possible to determine which component to bind to a property using any other technique, as well as to ignore a property. Methods annotated with @Action can be bound to JButtons and other widgets following the same logic used for properties. You can find out more about how the binding works by reading the docs.

Besides that basic binding features, genesis also makes it possible to enable/disable components based on conditions (using @EnabledWhen), making them visible/hide them (using @VisibleWhen), populate tables, combos, lists etc. with a java.util.List or an array (using @DataProvider) and much more. It is also fully compatible with Java 1.4 and has many other non-UI related features, such as transparent remoting (which I blogged almost two years ago).

To finish the big announcement day, a SWT binding is now in HEAD and should be released in the next few days. So if you are developing a desktop application that uses either Swing, SWT or Thinlet, take a look at genesis.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Very neat, MIchael :)

    Posted by: evanx on August 28, 2006 at 06:24 AM

  • neat indeed. However we shouldn't forget actions. Actions can be put in menus and bound to keyboard, have menmonics, icon...these features should be setup also, along with the bindings.
    GUI via visual editor using something like this could come closer to those those who code GUI manualy.

    Posted by: hrgdavor on August 28, 2006 at 07:10 AM

  • Hi hrgdavor

    The genesis binding will work just fine for the situation you have just mentioned, unless I've missed something. Could you please ellaborate?

    Posted by: mister__m on August 28, 2006 at 07:34 AM

  • Why use annotation when you could use reflection ? It's very simple to associate a component name with a bean property.
    And I agree with hrgdavor post, a GUI can by very complicated than don't lose time trying to automate GUI creation process, use GUI Designer is much more simple.

    Posted by: onorato on August 29, 2006 at 12:41 AM

  • my bad, I did'n read it all through. And my thoughts also stranded away since I saw this as an oportunity to bring closer together hand coded GUI and visual editors. Naming conventions and frameworks like this could make it possible to have visual editor without tons of junk code.
    My thoughts on the project are:
    - All things supported by Action interface should be supported, or even more.. (I have no concrete idea jus yet)
    - these Actions should be available through getActionMap() for example
    - some properties should be defined indirectly (action name "button.save") (icon=save_icon)
    - keyboard shortcuts could be assigned
    - maybe this is not for this project, but a broader good coding practice could be enforced along with the framework.
    - not to complicate too much some icon provider could just search for the icon above in : "icons/save_icon.png"

    in the binding example: https://genesis.dev.java.net/nonav/3.0-EA3/maven-site/en/binding.html
    button is created like this:

    JButton login = new JButton();
    login.setText("Login");
    login.setName("login");
    buttonPanel.add(login);

    I would prefer

    @Action("login","Login","login_icon")
    or
    @Action("login","Login")
    @ActionIcon("login_icon")
    .....

    and then

    buttonPanel.add(new Jbutton(getActionMap().get("login")));

    After that button could have translatable text, an icon, a mnemonic...
    Even if we just define @Action for the method, with method name used as internal code, all the properties could be setup into an action which would be available by calling getActionMap()

    Posted by: hrgdavor on August 29, 2006 at 01:17 AM

  • Hi onorato,

    Why use annotation when you could use reflection ? It's very simple to associate a component name with a bean property.

    Annotations are not being used for that. As you can see in the example, no bean property is annotated. Besides that, genesis doesn't force you to use annotations at all; you just need to produce a FormMetadata instance somehow.

    And I agree with hrgdavor post, a GUI can by very complicated than don't lose time trying to automate GUI creation process, use GUI Designer is much more simple.

    You are totally free to use Matisse with genesis. That is the idea, actually. genesis just makes it easier to bring your editor-generated user interface to life.

    Posted by: mister__m on August 29, 2006 at 06:48 AM

  • Hi hrgdavor,

    Now I've followed you. I do think producing javax.swing.Action instances from the form would be useful. I am just not sure if they should all be exposed by default in ActionMap or if genesis itself should provide a way to configure instance details, especially since the binding model proposed by genesis is UI-toolkit independent and the concept implemented by javax.swing.Action may not be available in all platforms.
    I've filed an issue to track your idea. If you want to provide additional information or rationale for the way it should work, feel free to post your comments there. We really appreciate user feedback.

    Posted by: mister__m on August 29, 2006 at 10:03 AM

  • Nice! but I have a question, how does Genesis relate to the databinding JSR ? (https://databinding.dev.java.net/)

    Posted by: aalmiray on August 29, 2006 at 02:53 PM

  • looks good.
    How can I use just the binding part of genesis framework with minimal dependency on other libs. Hope it is as modular as Spring etc.

    Posted by: tsawan on August 29, 2006 at 11:35 PM

  • Hi aalmiray,

    Well, first of all, I think you are referring to the Bean Binding JSR ( JSR-295 ), not the Data Binding JSR ( JSR-227 ), since the URL you pointed to should be the basis for JSR-295. With that in mind, there are many differences:


    The original SwingLabs project was targeted at Swing; genesis already works with Swing, SWT and Thinlet;
    Most of the planned features for this project are already implemented by genesis (actually, genesis implemented them for Thinlet long before the plan doc for databinding was written);
    genesis has support for declarative conditions and several other non-UI related features not supported by the project or the JSR;
    Currently, the JSR itself has no spec or RI whatsoever, so basically you cannot compare genesis, a working product, with a non-existent spec.


    When JSR-295 produces its spec, we hope we support a superset of what it does and support the standard when it makes sense.

    Posted by: mister__m on August 30, 2006 at 09:38 AM

  • Hi tsawan,

    We have just modularized genesis-client so it has very few dependencies and can be used as a simple library in other projects. This has changed in CVS HEAD and will be available in 3.0-EA4, as documented in issue # 364.

    Posted by: mister__m on August 30, 2006 at 09:49 AM

  • I'm terribly sorry for the confusion, you are right, I was referring to the Bean Binding JSR. Yes, sadly, it is still vaporware, I only know what I saw @ JavaOne, the spec guys hoped to get it rolling very quick, seems like that is not the case.
    Great to know that Genesis can do SWT and Thinlet too.

    Do you have a list of projects currently using Genesis ? it seems like Spring's RCP could benefit a lot from it =)

    Posted by: aalmiray on August 30, 2006 at 10:21 AM

  • Hi aalmiray,

    Although I am aware of several companies using genesis, we haven't asked permission to publish their names. I agree this would help to increase genesis adoption, for sure.

    Posted by: mister__m on September 04, 2006 at 08:22 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds