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