Griffon @ Svwjug

Post on 28-Jan-2015

107 views 0 download

Tags:

description

A Griffon talk presented @ SV web JUG on July 21st 09

Transcript of Griffon @ Svwjug

Welcome to the Desktop Revolution

What is Griffon ?

+ +

+ Sugar, Spice and everything Nice =

HelloWorld.java

public class HelloWorld { String name;

public void setName(String name) { this.name = name; } public String getName(){ return name; }

public String greet() { return "Hello "+ name; }

public static void main(String args[]){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.err.println( helloWorld.greet() ); }}

HelloWorld.groovy

public class HelloWorld { String name;

public void setName(String name) { this.name = name; } public String getName(){ return name; }

public String greet() { return "Hello "+ name; }

public static void main(String args[]){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.err.println( helloWorld.greet() ); }}

GroovierHelloWorld.groovy

class HelloWorld { String name def greet() { "Hello $name" }}

def helloWorld = new HelloWorld(name:"Groovy")println helloWorld.greet()

Swing

import java.awt.GridLayout;import java.awt.event.ActionListener;import java.awt.event.ActionEvent;import javax.swing.JFrame;import javax.swing.JTextField;import javax.swing.JButton;import javax.swing.SwingUtilities;

public class JavaFrame { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable(){ public void run() { JFrame frame = buildUI(); frame.setVisible(true); } }); } // next page ...

// continued ... private static JFrame buildUI() { JFrame frame = new JFrame("JavaFrame"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout( new GridLayout(3,1) ); final JTextField input = new JTextField(20); final JTextField output = new JTextField(20); output.setEditable(false); JButton button = new JButton("Click me!"); button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event) { output.setText(input.getText()); } }); frame.getContentPane().add(input); frame.getContentPane().add(button); frame.getContentPane().add(output); frame.pack(); return frame; }}

●The light at the end of the tunnel...

import groovy.swing.SwingBuilderimport static javax.swing.JFrame.EXIT_ON_CLOSE

new SwingBuilder().edt { frame(title: "GroovyFrame", pack: true, visible: true, defaultCloseOperation: EXIT_ON_CLOSE) { gridLayout(cols: 1, rows: 3) textField(id: "input", columns: 20) button("Click me!", actionPerformed: { output.text = input.text }) textField(id: "output", columns: 20, editable: false) }}

What is going on?

Each node is syntactically a method call

All of these method calls are dynamically dispatched

Most don’t actually exist in bytecode

Child closures create hierarchical relations

Child widgets are added to parent containers

SwingBuilder node names are derived from Swing classes

Remove the leading ‘J’ from a Swing class when present

SwingBuilder also supports some AWT classes like layouts

●Threads

Threading and the EDT

All painting and UI operations must be done in the EDT

Anything else should be outside the EDT

Swing has SwingUtilities using Runnable

Java 6 technology adds SwingWorker

However, closures are Groovy

For code inside EDT

edt { … }doLater { … }

For code outside EDT

doOutside { … }Build UI on the EDT

SwingBuilder.build { … }

Threading Example

action( id: 'countdown', name: 'Start Countdown', closure: { evt -> int count = lengthSlider.value status.text = count while ( --count >= 0 ) { sleep( 1000 ) status.text = count } status.background = Color.RED })

Threading Example

action( id: 'countdown', name: 'Start Countdown', closure: { evt -> int count = lengthSlider.value status.text = count doOutside { while ( --count >= 0 ) { sleep( 1000 ) edt { status.text = count } } doLater { status.background = Color.RED } }})

Binding

Binding Example

import groovy.swing.SwingBuilder

new SwingBuilder().edt { frame( title: "Binding Test", size: [200, 120], visible: true ) { gridLayout( cols: 1, rows: 2 ) textField( id: "t1" ) textField( id: "t2", editable: false ) } bind(source: t1, sourceProperty: "text", target: t2, targetProperty: "text")}

Binding Example

import groovy.swing.SwingBuilder

new SwingBuilder().edt { frame( title: "Binding Test", size: [200, 120], visible: true ) { gridLayout( cols: 1, rows: 2 ) textField( id: "t1" ) textField( id: "t2", editable: false, text: bind(source: t1, sourceProperty: "text") ) }}

Binding Example

import groovy.swing.SwingBuilder

new SwingBuilder().edt { frame( title: "Binding Test", size: [200, 120], visible: true ) { gridLayout( cols: 1, rows: 2 ) textField( id: "t1" ) textField( id: "t2", editable: false, text: bind{ t1.text } ) }}

Convention over Configuration

Don't repeat yourself (DRY)

MVC Pattern

Testing supported “out of the box”

Automate repetitive tasks

Convention over Configuration

Java Desktop Application Conventions are MIA

Very few official examples

No Blueprints (Like Java EE Blueprints)

We have to create our own

Following Grails Patterns

Source Files Segregated by Role

Standardize App Lifecycle (like JSR-296)

Automated Packaging (App, WebStart, Applet)

Lyfecycle Scripts

Lifecycle Scripts are in griffon-app/lifecycle

Lifecycle Events modeled after JSR-296

Initialize

Startup

Ready

Shutdown

Don't Repeat Yourself

How? Use a Dynamic Language!

With Closures/Blocks

With terse property syntaxmyJTextArea.text = "Fires Property Change"

With terse eventing syntaxbutton.actionPerformed = {println 'hi'}

With Rich Annotation Support@Bindable String aBoundProperty

Most of this impacts the View Layer

See JavaOne 2008 TS-5098 - Building Rich Applications with Groovy's SwingBuilder

Built-in Testing

Griffon has built in support for testing

create-mvc script creates a test file in test/integration

Uses GroovyTestCase

See JavaOne 2008 TS-5101 – Boosting your Testing Productivity with Groovy

Griffon doesn’t write the test for you

test-app script executes the tests for youBootstraps the application for you

Everything up to instantiating MVC Groups

Testing Plugins

Sometimes apps need more involved testing

fest Fluent interface for functional swing testing

easybBehavioral Driven Development

code-coverage – CoberturaLine Coverage Metrics

jdependCode quality metrics

codenarcStatic code analysis

Automate Tasks

command line interface

Scripts and events

plugins

builders: SwingX, JIDE, Flamingo, Trident , CSS, JavaFX and more

miscellaneous: installer (IzPack, RPM, OSX app bundles), Splash, Wizard, Scala

●Griffon's Roadmap

Resources

http://griffon.codehaus.org

http://griffon.codehaus.org/Builders

http://griffon.codehaus.org/Plugins

http://groovy.dzone.com

twitter: @theaviary

Griffon in Action (2010)

● http://manning.com/almiray

● http://groovymag.com

Groovy, Grails, Griffon and more!

Questions

●Thank you!

Image Credits

http://www.flickr.com/photos/fadderuri/841064754/

http://www.flickr.com/photos/colorloose/3539708679/

http://www.flickr.com/photos/icultist/2842153495/

http://www.flickr.com/photos/bishi/2313888267/

http://www.flickr.com/photos/kirimobile/2581287574/

http://www.flickr.com/photos/chelseaaaaaa/3564365301/

http://www.flickr.com/photos/psd/2086641/