Download NetBeans!

20090609 Tuesday June 09, 2009

How to Incorporate a Wizard into a Griffon Application (Part 2)

Let's make the Griffon wizard a bit more realistic than in yesterday's example.

  1. Use the same approach as outlined yesterday to create a second panel in the wizard. When prompted for a name, type "Two".

  2. In the controller, change the action to the following:
    def action = { evt = null ->
            def wizard = wizard( title: "Customer Order Wizard", pages: ["One", "Two"], resultProducer: [
                    //The Cancel button cancels:
                    cancel: { settings ->
                        return true
                    },
                    //Not sure what the 'data' is for:
                    finish: { data ->
                        return data
                    }
                ] )
            def result = showWizard(wizard)
            view.ta.text =
    """
    Name: ${result.tf1}
    Address: ${result.tf2}
    City: ${result.tf3}
    
    Order
    --------------------------
    ID: ${result.tf4}
    Name: ${result.tf5}
    Description: ${result.tf6}
    """
    
    }

    Note: The triple quotation marks are Groovy string concatenators, replacing the + construction common to Java.

  3. Add the MigLayout JAR (easy way to get it is to look at the Griffon 'Greet' example) to your application classpath.

  4. Change the "OneWizardPage.groovy" (in "griffon-app/wizards") to the following:
    import net.miginfocom.swing.MigLayout
    
    class OneWizardPage {
    
        def stepId = "step1" // must be unique per WizardPage
        def description = "Customer Details"
        def autoListen = true
    
        def pageContents = {
            panel(border:lineBorder(1, color: java.awt.Color.black), layout:new MigLayout('fill')) {
                label( text: "Name:" )
                textField( name: "tf1", text: "", columns: 20, constraints: "wrap" )
                label( text: "Address:" )
                textField( name: "tf2", text: "", columns: 20, constraints: "wrap" )
                label( text: "City:" )
                textField( name: "tf3", text: "", columns: 20 )
            }
        }
    
        // Either return a String that indicates a problem
        // or return a null value indicating no problem
        def onValidate = { component, /*PropertyChangeEvent*/ event ->
            return null // no problems
        }
       
    }

    Note: Hurray for MigLayout, without which you wouldn't have the "constraints" property in the textFields. For further details, read How Griffon Helps MigLayout and MigLayout: Inevitable Choice for Griffon Users? (Another article to look at is Porting to Griffon, though MigLayout isn't used there.)

  5. Next, define the "TwoWizardPage.groovy" (in "griffon-app/wizards") to the following:
    import net.miginfocom.swing.MigLayout
    
    class TwoWizardPage {
       def stepId = "step2" // must be unique per WizardPage
       def description = "Product Details"
       def autoListen = true
    
       def pageContents = {
          panel(border:lineBorder(1, color: java.awt.Color.black), layout:new MigLayout('fill')) {
                label( text: "ID:" )
                textField( name: "tf4", text: "", columns: 20, constraints: "wrap" )
                label( text: "Name:" )
                textField( name: "tf5", text: "", columns: 20, constraints: "wrap" )
                label( text: "Description:" )
                textField( name: "tf6", text: "", columns: 20, constraints: "wrap" )
            }
       }
    
       // Either return a String that indicates a problem
       // or return a null valud indicating no problem
       def onValidate = { component, /*PropertyChangeEvent*/ event ->
          return null // no problems
       }
       
    }

    Note: The textField names are very important. The controller has access to them, via "${result.tf1}" and so on in the action defined in the controller.

  6. Run the application.

    Click the "New" menu item, as before. When you fill out the first step, you should see something like this:

    Notice how the "constraints" property wraps the component after the textFields onto the next line, meaning that we don't need to wish we had something like the Matisse GUI Builder at all. After filling the above out, click Next, fill out the Order form, and you should see something like this:

    Click Finish and here's the result:

What I'm curious about is how to connect my Griffon application to a database. That would make it possible to fill the wizard panels with customer and product data from a database.

Jun 09 2009, 03:19:27 PM PDT Permalink

Trackback URL: http://blogs.sun.com/geertjan/entry/how_to_incorporate_a_wizard1
Comments:

Here are a few pointers:

A. setup a datasource
B. setup a db service
C. wire the service to the wizard pages

while Griffon does not provide any datasource helpers like Grails does (yet) you can emulate them by:

1. adding the file griffon-app/conf/DataSource.groovy
2. add spring jars to your app's lib directory
3. create an event script in scripts/_Events.groovy
4. make sure to listen for eventCompileEnd, this is your cue to compile DataSource.groovy (this step is optional if Griffon does not perform this task already).
5. load the datasource at startup, you can either place the code on lifecycle/Initialize.groovy (make sure it is done outside the EDT) or by registering an application event listener (add onInitializeStart() to griffon-app/conf/Events.groovy)
6. place the datasource on the app's config space or another globally accessible space

that should take care of #A. #B & #C can be solved by

1. creating a service class on griffon-app/services/MyDbService.groovy, make sure it is a singleton (@Singleton comes in handy) and that a setDataSource() method is provided
2. make use of JdbcTemplate and DataSource to perform db calls
3. wizard pages should call MyDbService.getInstance().makeYourDbCallHere()

this is a very rough approach, it is not perfect. Certainly a dbplugin would come in handy to automatize most of the steps, perhaps even drop Spring and go directly for GSQL.

Posted by Andres Almiray on June 09, 2009 at 03:55 PM PDT #

Hi Geertjan,

Your article is great.
But this Griffon plugin is pre Alpha.
I installed this plug in on NetBeans 6.7RC2.
Then I found that I can not recognize this plugin at the "Installed Plugins" TAB at the plugin manager.
So we can not uninstall these.
More over I found that when this Griffon plugin is installed,then Grails project is destroied.
The behaviour of pre-existed Grails project
looks the same of Griffon's project.
The Griffon's 3 plugins had better joined to one.

Where is the repository of this project?
Is this project opensourced?

Posted by Sotoiro Terashima on June 10, 2009 at 11:12 PM PDT #

Yes, it is pre-Alpha. That's what the plugin page tells you. It also tells you that the Grails plugin is destroyed when you install the Griffon plugin. So, why are you telling me something that I have already told you on the plugin's page? Also, did you notice that the plugins page tells you to installed NetBeans IDE 6.7 Beta?

Posted by Geertjan on June 10, 2009 at 11:35 PM PDT #

Excuse me,but I could not notice your comment:
"Grails support will be visible but will not work anymore, in pre-Alpha anyway. Next release of plugin will fix that. "
in item 4 on the plugin page.
>Also, did you notice that the plugins page tells you to installed NetBeans IDE 6.7 Beta?
Yes,I noticed "or, probably, above" in the item 1 also.
1.Install NetBeans IDE 6.7 Beta (or, probably, above),.......

Posted by Sotohiro Terashima on June 11, 2009 at 05:31 AM PDT #

Hi Geertjan,

First of all, thank you for the Netbeans griffon plugin.

Here is my experience using the plugin on Netbeans 6.7.
The solutions presented must be viewed in the perspective that I regularly use Eclipse and I am not aware for the Netbeans way of doing things, so, be patient.

My configuration is as follows:
Linux Debian/Sid with Sun Java 1.6.0, Groovy 1.6.3, Griffon 0.1.2, Netbeans 6.7 and Griffon plugin pre-alpha dated Jun 03, 2009

There are 3 problems and 4 wishes that could solve them

/A/ While following your "How to Incorporate a Wizard into a Griffon Application (Part 2)"

** Problem: The editor is unable to resolve the imports of groovy.beans.Bindable and net.miginfocom.swing.MigLayout
- The application runs from the popup menu but fails with java.lang.NoClassDefFoundError when calling the wizard form that has the migLayout.

** Things that I tried but did not work
- Set the classpath to point to the jars
- Put the jars in the lib directory of griffon
- Prepend the jar to Tools->Libraries->Groovy 1.5.7

** Solution: Link or copy the required jars to the lib directory of the application
(griffon-0.1.2/lib/groovy-all-1.6.3.jar and migLayout-3.7/*.jar)
- The editor and the application function ok.

** Wish 1: The New Griffon Application could create the link for groovy-all
** Wish 2: In the project view a Library branch (mapped to lib) with a popup wizard able to add jars

/B/ While following the same how to, the wizard directory does not appear in the project view

** Wish 3: A Plugins branch with children the directories that are created by the plugins

/C/ While running the Sample applications of griffon

** Problem: The editor was unable to resolve classes that belong to the application
e.g see: Greet/griffon-app/controllers/greet/TimelinePaneController.groovy

- The reason is that the griffon run-app compiles and runs the application ($APPLIC) ok but stores the classes
to the $HOME/.griffon/0.1.2/projects/$APPLIC/classes directory which is not known to the netbeans project
- But the compiled classes are also stored in the taging directory into the jar $APPLIC.jar

** Solution (hack): Link or copy the staging/$APPLIC.jar to the lib/$APPLIC-old.jar

The editor works fine and the only drawback is that you have a redundant $APPLIC-old.jar in the staging directory after each compilation.

** Wish 4: The New Griffon Application could create a link named $APPLIC-old.jar in the lib directory pointing
to an empty $APPLIC.jar in the staging directory and if a copy is prefered then make the copy with a build rule after each compilation.

Thank you in advance

George Famelis

Posted by Famelis George on July 25, 2009 at 11:05 AM PDT #

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed