X

Geertjan's Blog

  • June 9, 2009

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

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

Join the discussion

Comments ( 5 )
  • Andres Almiray Tuesday, June 9, 2009

    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.


  • Sotoiro Terashima Wednesday, June 10, 2009

    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?


  • Geertjan Wednesday, June 10, 2009

    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?


  • Sotohiro Terashima Thursday, June 11, 2009

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


  • Famelis George Saturday, July 25, 2009

    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


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