I’ve come to love the Python language for its elegant syntax combined with powerful constructs like comprehensions. Jython allows me to take Python to the next level by allowing it to interact with my existing JVM-compatible code. Now I want to extend that even further and allow myself (and you, of course) to integrate Jython with Griffon, a framework for building desktop applications in Groovy.

Introducing the Jython plugin for Griffon

The Jython plugin enables compiling and running Jython code on your Griffon application. You don’t even need to install Jython manually. A Jython REPL is available with access to your Groovy/Java classes if you use:

griffon jython-repl

You can even load Jython scripts on-the-fly by putting them in MyGriffonApp/griffon-app/resources/jython!

In the rest of the article, we are going to create a simple application that mixes Griffon and Jython using the Griffon-Jython plugin.

Jython Sample Application

Getting started with griffon-jython

It’s easy to setup Griffon, and you’ll find instructions here and downloads here. Once you’re done, you can create a Griffon app and install the jython plugin by typing:

griffon create-app MyGriffonApp
cd MyGriffonApp
griffon install-plugin jython

Now that we’ve installed the Jython plugin, you can create a Jython class on your command-line:

# Creates MyGriffonApp/src/jython/com/mypkg/MyJythonClass.py
griffon create-jython-class com.mypkg.MyJythonClass

Let’s create a Jython class that greets the user when a button is clicked.

from com.mypkg import IGreeter

class MyJythonClass(IGreeter):
  def __init__(self):
    pass

  def greet(self, who, model):
    greeting = 'Hello %s from Jython!' % str(who)
    model.setOutput(greeting)

Jython classes are exposed to Griffon using an Object Factory Pattern as suggested in the Definitive Guide To Jython, Chapter 10. Therefore, we create a Java (well, Groovy) interface that MyJythonClass will extend to allow Griffon to get at the proper method implementations. It sounds rather complicated, but it really is quite simple. Let’s create the IGreeter interface to show you what I’m talking about:

package com.mypkg

public interface IGreeter {
  // Same signature as our Jython method
  public void greet(String greetee, def model)
}

Our greet() method accepts a String (the textField input) and a model of unspecified type.

Griffon auto-generates MVC classes for you, so we can use those. You’ll find them in the MyGriffonApp/griffon-app/{models,views,controllers} directories. We are going to change those for our app! Here is the aforementioned Model:

package com.mypkg
import groovy.beans.Bindable

class MyGriffonAppModel {
    @Bindable String input = ''
    @Bindable String output = ''
}

Groovy implicitly creates get/setInput() methods and allows them to be bound (to the View textField value, e.g.). Here is that MyGriffonAppView:

package com.mypkg

application(title:'Griffon Jython Sample', pack:true, locationByPlatform:true) {
  gridLayout(cols: 1, rows: 2)
  //Note the ID on this textField
  textField(id: "input", columns: 20)
  button("Click me!", actionPerformed: controller.handleClick)
  bean(model, input: bind {input.text})
}

Finally, the most critical part of our application that will interact with our Jython class, the MyGriffonAppController:

package com.mypkg

import java.beans.PropertyChangeListener
import griffon.jython.JythonObjectFactory
import javax.swing.JOptionPane

class MyGriffonAppController {
  // Values auto-injected
  def model
  def view
  def greeter

  def mvcGroupInit(Map args) {
     // When our model output has changed, show a dialog
     model.addPropertyChangeListener("output", { evt ->
       if(!evt.newValue) return
       doLater {
         JOptionPane.showMessageDialog(app.windowManager.windows[0],
           evt.newValue, "Message from Jython", JOptionPane.INFORMATION_MESSAGE)
       }
     } as PropertyChangeListener)

     // Instantiate MyJythonClass
     JythonObjectFactory factory =
         new JythonObjectFactory(IGreeter.class, 'MyJythonClass', 'MyJythonClass')
     greeter = (IGreeter) factory.createObject()
   }

  def handleClick = { evt = null ->
    if(!model.input) return
    model.output = ""
    // invoke Jython class (outside EDT)
    doOutside {
      greeter.greet(model.input, model)
    }
  }
}

There you have it! Now we can utilize such Jython greatness as generators and list comprehensions!

Further reading

The Griffon Guide is the best place to go for Griffon documentation. You can find more comprehensive documentation for the Jython plugin on the official plugin page. As always, this stuff is completely open-source, and you can find all of the code and submit suggestions and issues at the GitHub repository.

Posted on .