SlideShare a Scribd company logo
Introduction to Griffon

     James Williams
About Me

● Co-founder of Griffon

● Author of "Learning HTML5
  Game Programming"
  http://amzn.to/HTML5-Game-Book

● Blog: http://jameswilliams.be

● Twitter: @ecspike
Agenda

 ● What is Griffon?
 ● Common Griffon Commands
 ● Model - View - Controller
 ● MigLayout
 ● Binding
 ● Plugins
 ● Validation
 ● Lots of code

Code for this demo: https://github.com/jwill/Conference-Demos
What is Griffon?

● Apache 2 Licensed

● http://griffon.codehaus.org

● Inspired by Grails and the Swing Application Framework

● Extensible with plugins and addons

● Deployable to Webstart, Applet, or single jar file

● Now to Github!
Common Griffon Commands

● create-app

● create-mvc

● test-app

● run-app

● help

● package

● Form: griffon <environment> command <options>
Griffon Aliases

 ● create-app

 ● create-mvc   => cM

 ● test-app     => tA

 ● run-app      => app

 ● help         => h

 ● package      => p

You can even create your own with the create-alias command.
Griffon Views

● Represent the presentation layer of the MVC triad

● Use Domain Specific Languages called UI Builders

● SwingBuilder is bundled

● Additional builder available as plugins (SwingXBuilder,
  JIDE, MacWidgets, etc)
Sample Griffon View File

package hello

application(title: 'Hello',
  preferredSize: [320, 240],
  pack: true,
  //location: [50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [/* truncated */]) {
    // add content here
    label('Content Goes Here') // delete me
}
Code

cd <GRIFFON INSTALL DIR>

cd samples/SwingPad

griffon app
Common Widgets

● label

● button

● checkBox, radioButton

● textField

● textArea

● panel

● hbox, vbox
Code

import javax.swing.JOptionPane

button('Click', actionPerformed: {
JOptionPane.showMessageDialog(
        null, "Button clicked at ${new Date()}"
     )
})
Crash course in MigLayout

● Grid-based LayoutManager

● Human-readable

● Docking (BorderLayout)

● Absolute Positioning

● Constraints

● Units (px, mm, cm, pts, in, %)
Crash course in MigLayout

● wrap, newline

● w/width, h/height

● Docking (BorderLayout)

● gap

● span

● cell [column] [row]
Code

import net.miginfocom.swing.MigLayout

panel(layout:new MigLayout()) {
label(text:'label')
label(text:'Cell 1 1 ', constraints:'cell 1 1')
}
Code

import net.miginfocom.swing.MigLayout

panel(layout:new MigLayout()) {
label(text:'Text', constraints:'wrap')
label(text:'Text2 ')

label(text:'Text3', constraints:'w 50px, newline')
label(text:'Text4 ')

textField(columns:10, constraints:'span 2, newline')
}
Griffon Models

● Hold data for the MVC triad

● Can send/receive(@Bindable) data to/from widgets in the
  view

● Can do Grails-style validation (plugin)
Sample Griffon Model file

import groovy.beans.Bindable

class HelloModel {
  // @Bindable String propName
}
Binding Forms

textField(text:bind{model.property})

textField(text:bind(source:model, sourceProperty:"data"))

textField(text:bind(target:model, targetProperty:"data"))
Griffon Controllers

 ● Brains of the MVC triad

 ● Contain actions for the triad

 ● Injected with references to the model and view
Sample Griffon Controller File

class HelloController {
   // these will be injected by Griffon
   def model
   def view

  // void mvcGroupInit(Map args) {
  // // this method is called after model and view are injected
  // }

  // void mvcGroupDestroy() {
  // // this method is called when the group is destroyed
  // }
Griffon Plugins

● Extend app functionality at runtime or compile-time

● Can be as simple as adding a couple jars...

● Or as complex as creating a custom builder to use them

● Common areas:

   ○ UI Toolkits

   ○ Dependency Injection

   ○ Persistence
Code

(From inside a Griffon app directory)

griffon list-plugins
griffon lP

griffon plugin-info <name of plugin>
Creating A ToDo Application
Code

griffon create-app TodoApp

<wait... wait... wait...>

griffon install-plugin swingx-builder
griffon install-plugin swingxtras-builder
griffon install-plugin validation
Code (/src/main/todoapp/...)

class TodoItem {
String todoText
Date dueDate
List <String>tags
      Boolean isDone
Boolean isSaved
public tagsToString() {
Arrays.sort(tags)
tags.join(',')
}
}
Code (/griffon-app/models/todoapp/.)

import groovy.beans.Bindable

class TodoModel {
@Bindable String todoText
@Bindable Date dueDate
@Bindable tagsText
List <TodoItem> todos
}
Code (griffon-app/views/todoapp/...)

size: [640,480],
locationByPlatform:true,
layout: new MigLayout()) {
  // Add Todo field
  jxtextField(id:'todoField', columns:45,
text:bind(target:model, 'todoText'),
constraints:'w 90%')
  promptSupport(todoField, prompt: "Add Todo, type here")
   button(id:'btnAdd', text:'Add', constraints:'w 10%, wrap')

}
Introduction to Griffon
Code (griffon-app/views/todoapp/...)

// More options (date, tags, etc)
jxtaskPane(title:'More Options', constraints: 'w 100%, spanx 2, wrap', layout:
new MigLayout()) {
label(text:'Due Date:', constraints:'wrap')
jxdatePicker(id:'datePicker', date:bind(target:model,'dueDate'),
constraints:'wrap')
label(text:'Tags', constraints:'wrap')
textField(id:'tagsField', columns:40, text:bind(target:model, 'tagsText'))
promptSupport(tagsField, prompt:'Enter tags comma separated')
}
Introduction to Griffon
Swing isn't slow, ...
... devs are just coding it badly
Don't do this!

JButton b = new JButton("Run query");
b.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
  runQueries();
  }
});
Threading in Swing

● All updates to the UI must happen on the single Event
  Dispatcher Thread(EDT)

● Nothing else should be executed on the EDT*

● Bad dev starts long running task, UI locks up until it is done

● SwingUtilities provides the following functions:
   ○ isEventDispatchThread()
   ○ invokeLater(Runnable),
        invoke Runnable when convenient
   ○ invokeAndWait(Runnable)
        invoke when convenient and wait for completion
(Swing) Threading in Griffon

● Encapsulates SwingUtilities and simple threading

● Adds closure for running a task outside the EDT

● Available closures:
   ○ doLater { ... }  ==> SwingUtilities.doLater
   ○ edt{ ...}        ==> SwingUtilities.invokeAndWait
   ○ doOutside{..} ==> Spawns new Thread if inside EDT

● Griffon 0.9.2+ encloses controller actions with doOutside by
  default (can be turned off)
Code (griffon-app/controllers/...)

def load = {
doOutside {
def todos = model.derby.all()
todos.each {
def todo = TodoItem.fromMap(it)
model.todos.add(todo)
}
}
}
Adding a table of todo items
The old way ...

 ● A very brittle TableModel

 ● Hard to update and sort items

 ● Hard to map between POJOs and rows
Code (SwingPad)

import javax.swing.table.DefaultTableModel
def a = new DefaultTableModel(['A','B','C'] as String[], 0)
a.addRow(1,2,3)
a.addRow(4,5,6)
a.addRow(7,8,9)

scrollPane {
jxtable(model:a)
}
Code (griffon-app/views/todoapp/...)

...
jxtitledPanel(title:'Tasks') {
scrollPane {
jxtable(id:'table', model:model.todoTableModel)
}
}
GlazedLists

● Easy data model management for:
   ○ JComboBox,
   ○ JList
   ○ JTable

● Provides easy dynamic sorting and filtering

● Supports both SWT and Swing

● Supports concurrency

● Link: http://glazedlists.com
BasicEventList

● Compatible with ArrayList and Vector

● Stores the items for your List or Table

● Parameterized around POJO
    BasicEventList todos = new BasicEventList<TodoItem>()
● Adds listeners for changes in the list
BasicEvent<Widget>Model

● Receives changes from BasicEventList and pushes them to
  the widget

● BasicEventListModel and BasicEventComboModel take
  only a BasicEventList (POJOs to display) as a parameter

● JTables require a bit more definition
TableFormat

● Interface that defines how the table is displayed in the GUI

● By default is not editable after initialization

● Required functions:
   ○ getColumnCount()
   ○ getColumnName(int)
   ○ getColumnValue(obj, int)
WritableTableFormat

● Interface allowing editing of fields

● Can set granular edit policy with isEditable

● Uses default field editor (usually a JTextField)

● Required functions:
   ○ isEditable(obj, column)
   ○ setColumnValue(obj, value, column)
AdvancedTableFormat

● Interface that allows custom cell renderers
    For example: DatePickers, Check boxes, Sliders, etc.

● JTables set policies on how to render a cell with a certain
  class type

● JXTables do sorting and filtering so a separate comparator
  is not needed

● Required functions:
   ○ getColumnClass(int)
   ○ getColumnComparator(int)
Adding a bit of Swing glue:
Table Editors and Renderers
TableEditor vs TableRenderers

● Any Swing component can be an editor or renderer

● TableEditors show when that cell is being edited

● TableRenderers appear in all other cases

● Can be mixed an matched
   For example: a default renderer but a specialized renderer
Default TableRenderers
     Class           Renderer Component
     Boolean*        JCheckBox*
     Number          JLabel, right-aligned
     Double, Float   JLabel, right-aligned with
                     coersion to String using
                     NumberFormat
     Date            JLabel, with coersion to String
                     using DateFormat


     Object          JLabel with object's toString()
                     value
Code (src/main/groovy)

class CheckBoxRenderer extends JCheckBox implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object
value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground())
setBackground(table.getSelectionBackground())
} else {
setForeground(table.getForeground())
setBackground(table.getBackground())
}
setSelected(value)
return this
}
}
Code (src/main/groovy)

class DatePickerEditor extends AbstractCellEditor implements TableCellEditor {
def component = new JXDatePicker()
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
component.setDate(value)
return component
}
public Object getCellEditorValue() {
return component.getDate()
}
}
Code (griffon-app/controllers/...)

// setup renderers and editors
view.table.setDefaultRenderer(Boolean.class, new CheckBoxRenderer())
view.table.setDefaultEditor(Boolean.class, new DefaultCellEditor(new
JCheckBox()))

view.table.setDefaultEditor(Date.class, new DatePickerEditor())
Code (griffon-app/controllers/...)

// table model listener
model.todoTableModel.addTableModelListener([tableChanged:
{evt ->
def i = evt.getFirstRow()
def j = evt.getLastRow()
if (i == j && evt.getType() == TableModelEvent.UPDATE) {
// do something with the update date
}
}] as TableModelListener)
Code (griffon-app/controllers/...)

def deleteCompleted = {
  def lock = model.todos.getReadWriteLock().writeLock()
  lock.lock()
  def list = model.todos.findAll{item ->
  item.isDone == true
  }
  list.each { item ->
  model.derby.remove(item.id)
  model.todos.remove(item)
  }
  lock.unlock()
  }
Introduction to Griffon
Saving to disk
Introducing Deckchair

● Modeled after Lawnchair, a lightweight JSON store (JS)

● Written in Groovy

● Uses an adapter-implementation model for persistence
   Derby is the only implemented backend for Deckchair
● Provides more flexibility than direct use of backends

● Link: http://github.com/jwill/deckchair
Deckchair API

● save, saves a single object

● get, retreives an object

● each, executes code for every item in the result set

● find, finds objects using a closure

● all, returns all objects in the set

● nuke, destroys all objects in the set

● remove, destroys a single object
Deckchair Derby Internals

● Creates a table with:
   ○ id, 36-character VARCHAR
   ○ timestamp, BIGINT
   ○ value, LONG VARCHAR (about 32,000 characters)

● Objects are serialized to JSON strings on insertion

● Only the uniqueness of the id field is enforced

● Good for small amounts of data and demos

● Good for data models that aren't exactly pinned down yet
Code

// from model
def derby = new Deckchair([name:'todos', adaptor:'derby'])

//loading todos
def todos = model.derby.all()

// save function with optional closure to print status after completion
model.derby.save(changedTodo.toMap(),
    {obj -> println obj; println "saved todo"}
)
Validation
GValidation Plugin

● Provides Grails style validation and messages

● Uses a Grails-like DSL

● Supports custom constraints in addition to built-in types

● Provides visual cues for incorrect data

● Can internationalize error messages with the Griffon i18n
  plugin
Code (griffon-app/models/...)

package todo
import jwill.deckchair.*

import groovy.beans.Bindable
//...

@Validatable
class TodoModel {
@Bindable String todoText
@Bindable Date dueDate
@Bindable tagsText
//...
static constraints = {
todoText(blank:false)
dueDate(nullable:true)
tagsText(blank:true)
}
}
Supported Validators

● blank                ● min

● creditCard           ● minSize

● email                ● notEqual

● inetAddress          ● nullable

● inList               ● range

● matches              ● size

● max                  ● url
Validation an object

def addItem = {
if (model.validate()) {
// save file
} catch(Exception ex) { }

} else {
model.errors.each{error ->
println error
}
}
}
Showing a error component

jxtextField(
   id:'todoField',
   columns:45,
   text:bind(target:model, 'todoText'),
   constraints:'w 90%',
   errorRenderer:'for: todoText, styles: [highlight, popup]'
)
Introduction to Griffon
Printing in Griffon
There once was a java.net
 project called EasyPrint
It was a casualty to the Java.
    net/Kenai conversion
              :(
From HTML to PDF
Code (griffon-app/controllers/...)

def builder = new MarkupBuilder(writer)

builder.html {
head{
title('My Todo List')
}
body {
h2("My Todo List")
br {}
table (width:'90%', border:1, 'border-spacing':0){
tr { td('Completed'); td('Description'); td('Due Date'); td('Tags')   }
model.todos.each { item ->
tr {
if (item.isDone) { td('Done') } else { td() }
td(item.todoText)
td(item.dueDate)
td(item.tagsToString())
}
}
}
}
}
Code (griffon-app/controllers/...)

def createPDF = {
  createHTML()
  def file = File.createTempFile("todos","txt"); file.write(writer.toString())
  def docBuilder = DocumentBuilderFactory.newInstance().
newDocumentBuilder()
  def doc = docBuilder.parse(file)

  def renderer = new ITextRenderer()
  renderer.setDocument(doc, null)

  def outputFile = "todos.pdf"
  def os = new FileOutputStream(outputFile)
  renderer.layout(); renderer.createPDF(os); os.close()

  edt {
  JOptionPane.showMessageDialog(null, "PDF created.")
  }
  }
Questions ?

More Related Content

PPT
Ratpack - Classy and Compact Groovy Web Apps
PPTX
Building Web Apps in Ratpack
PPT
Testing of javacript
PDF
Maven 3.0 at Øredev
PDF
PyCon Korea 2019 REST API Document Generation
PDF
Aprende, contribuye, y surfea Cloud Native Java - GuateJUG 2021
PDF
"How to Use Bazel to Manage Monorepos: The Grammarly Front-End Team’s Experie...
PDF
EuroPython 2013 - Python3 TurboGears Training
Ratpack - Classy and Compact Groovy Web Apps
Building Web Apps in Ratpack
Testing of javacript
Maven 3.0 at Øredev
PyCon Korea 2019 REST API Document Generation
Aprende, contribuye, y surfea Cloud Native Java - GuateJUG 2021
"How to Use Bazel to Manage Monorepos: The Grammarly Front-End Team’s Experie...
EuroPython 2013 - Python3 TurboGears Training

What's hot (20)

PDF
Mastering Maven 2.0 In 1 Hour V1.3
PPTX
Geb+spock: let your functional tests live long and prosper
PDF
Whats New In Groovy 1.6?
PDF
Introducing Playwright's New Test Runner
PDF
Groovy in the Cloud
ODP
Continuous integration with Git & CI Joe
KEY
groovy & grails - lecture 9
PDF
Expressive Microservice Framework Blastoff
ODP
Vagrant move over, here is Docker
PDF
Виталий Редько "React + Redux: performance & scalability"
PDF
Perl Continous Integration
PDF
Laravel 4 package development
PDF
PyCon Korea - Real World Graphene
PDF
An Introduction to Gradle for Java Developers
PPTX
Jedi Mind Tricks for Git
PDF
Zend Framework 1.8 workshop
ODP
Django Seminar 08/17/2013
PDF
Grooscript greach
PDF
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
PDF
Hands on the Gradle
Mastering Maven 2.0 In 1 Hour V1.3
Geb+spock: let your functional tests live long and prosper
Whats New In Groovy 1.6?
Introducing Playwright's New Test Runner
Groovy in the Cloud
Continuous integration with Git & CI Joe
groovy & grails - lecture 9
Expressive Microservice Framework Blastoff
Vagrant move over, here is Docker
Виталий Редько "React + Redux: performance & scalability"
Perl Continous Integration
Laravel 4 package development
PyCon Korea - Real World Graphene
An Introduction to Gradle for Java Developers
Jedi Mind Tricks for Git
Zend Framework 1.8 workshop
Django Seminar 08/17/2013
Grooscript greach
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
Hands on the Gradle
Ad

Viewers also liked (7)

PDF
Intro to HTML5 Game Programming
ODP
SVCC Intro to Grails
PPS
Quien Soy Yo
PDF
ODP
Android Development
PPT
Berlin 6 Open Access Conference: Dieter Imboden
KEY
Introduction to WebGL and Three.js
Intro to HTML5 Game Programming
SVCC Intro to Grails
Quien Soy Yo
Android Development
Berlin 6 Open Access Conference: Dieter Imboden
Introduction to WebGL and Three.js
Ad

Similar to Introduction to Griffon (20)

PDF
Griffon @ Svwjug
ODP
Qt Workshop
PDF
Android Best Practices
PPTX
從零開始學 Android
PPT
CodeMash - Building Rich Apps with Groovy SwingBuilder
KEY
Gwt and Xtend
PDF
Fragments anyone
PDF
Annotation Processing
PPTX
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
PDF
Gephi Toolkit Tutorial
PDF
Flash develop presentation
PPT
Griffon Presentation
PDF
MOPCON 2014 - Best software architecture in app development
PDF
Advanced Dagger talk from 360andev
PDF
Go 1.10 Release Party - PDX Go
PDF
PPTX
MEF Deep Dive by Piotr Wlodek
PDF
Mender.io | Develop embedded applications faster | Comparing C and Golang
PDF
Gradle For Beginners (Serbian Developer Conference 2013 english)
PPT
13.ppt Java power point presentation Java
Griffon @ Svwjug
Qt Workshop
Android Best Practices
從零開始學 Android
CodeMash - Building Rich Apps with Groovy SwingBuilder
Gwt and Xtend
Fragments anyone
Annotation Processing
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Gephi Toolkit Tutorial
Flash develop presentation
Griffon Presentation
MOPCON 2014 - Best software architecture in app development
Advanced Dagger talk from 360andev
Go 1.10 Release Party - PDX Go
MEF Deep Dive by Piotr Wlodek
Mender.io | Develop embedded applications faster | Comparing C and Golang
Gradle For Beginners (Serbian Developer Conference 2013 english)
13.ppt Java power point presentation Java

More from James Williams (12)

PDF
Griffon for the Enterprise
PPT
Game programming with Groovy
PDF
Java development with MongoDB
PDF
Enterprise Griffon
PDF
Porting legacy apps to Griffon
PPT
Using MongoDB With Groovy
PDF
Creating Voice Powered Apps with Ribbit
PDF
Griffon: Swing just got fun again
PPT
Griffon: Swing just got fun again
PPT
Extending Groovys Swing User Interface in Builder to Build Richer Applications
PPT
Boosting Your Testing Productivity with Groovy
ODP
Griffon: Re-imaging Desktop Java Technology
Griffon for the Enterprise
Game programming with Groovy
Java development with MongoDB
Enterprise Griffon
Porting legacy apps to Griffon
Using MongoDB With Groovy
Creating Voice Powered Apps with Ribbit
Griffon: Swing just got fun again
Griffon: Swing just got fun again
Extending Groovys Swing User Interface in Builder to Build Richer Applications
Boosting Your Testing Productivity with Groovy
Griffon: Re-imaging Desktop Java Technology

Recently uploaded (20)

PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Electronic commerce courselecture one. Pdf
PDF
KodekX | Application Modernization Development
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PPTX
A Presentation on Artificial Intelligence
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Modernizing your data center with Dell and AMD
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Encapsulation theory and applications.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Network Security Unit 5.pdf for BCA BBA.
Understanding_Digital_Forensics_Presentation.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Unlocking AI with Model Context Protocol (MCP)
Electronic commerce courselecture one. Pdf
KodekX | Application Modernization Development
20250228 LYD VKU AI Blended-Learning.pptx
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
A Presentation on Artificial Intelligence
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Big Data Technologies - Introduction.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Building Integrated photovoltaic BIPV_UPV.pdf
Modernizing your data center with Dell and AMD
The AUB Centre for AI in Media Proposal.docx
Encapsulation theory and applications.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...

Introduction to Griffon

  • 1. Introduction to Griffon James Williams
  • 2. About Me ● Co-founder of Griffon ● Author of "Learning HTML5 Game Programming" http://amzn.to/HTML5-Game-Book ● Blog: http://jameswilliams.be ● Twitter: @ecspike
  • 3. Agenda ● What is Griffon? ● Common Griffon Commands ● Model - View - Controller ● MigLayout ● Binding ● Plugins ● Validation ● Lots of code Code for this demo: https://github.com/jwill/Conference-Demos
  • 4. What is Griffon? ● Apache 2 Licensed ● http://griffon.codehaus.org ● Inspired by Grails and the Swing Application Framework ● Extensible with plugins and addons ● Deployable to Webstart, Applet, or single jar file ● Now to Github!
  • 5. Common Griffon Commands ● create-app ● create-mvc ● test-app ● run-app ● help ● package ● Form: griffon <environment> command <options>
  • 6. Griffon Aliases ● create-app ● create-mvc => cM ● test-app => tA ● run-app => app ● help => h ● package => p You can even create your own with the create-alias command.
  • 7. Griffon Views ● Represent the presentation layer of the MVC triad ● Use Domain Specific Languages called UI Builders ● SwingBuilder is bundled ● Additional builder available as plugins (SwingXBuilder, JIDE, MacWidgets, etc)
  • 8. Sample Griffon View File package hello application(title: 'Hello', preferredSize: [320, 240], pack: true, //location: [50,50], locationByPlatform:true, iconImage: imageIcon('/griffon-icon-48x48.png').image, iconImages: [/* truncated */]) { // add content here label('Content Goes Here') // delete me }
  • 9. Code cd <GRIFFON INSTALL DIR> cd samples/SwingPad griffon app
  • 10. Common Widgets ● label ● button ● checkBox, radioButton ● textField ● textArea ● panel ● hbox, vbox
  • 11. Code import javax.swing.JOptionPane button('Click', actionPerformed: { JOptionPane.showMessageDialog( null, "Button clicked at ${new Date()}" ) })
  • 12. Crash course in MigLayout ● Grid-based LayoutManager ● Human-readable ● Docking (BorderLayout) ● Absolute Positioning ● Constraints ● Units (px, mm, cm, pts, in, %)
  • 13. Crash course in MigLayout ● wrap, newline ● w/width, h/height ● Docking (BorderLayout) ● gap ● span ● cell [column] [row]
  • 14. Code import net.miginfocom.swing.MigLayout panel(layout:new MigLayout()) { label(text:'label') label(text:'Cell 1 1 ', constraints:'cell 1 1') }
  • 15. Code import net.miginfocom.swing.MigLayout panel(layout:new MigLayout()) { label(text:'Text', constraints:'wrap') label(text:'Text2 ') label(text:'Text3', constraints:'w 50px, newline') label(text:'Text4 ') textField(columns:10, constraints:'span 2, newline') }
  • 16. Griffon Models ● Hold data for the MVC triad ● Can send/receive(@Bindable) data to/from widgets in the view ● Can do Grails-style validation (plugin)
  • 17. Sample Griffon Model file import groovy.beans.Bindable class HelloModel { // @Bindable String propName }
  • 19. Griffon Controllers ● Brains of the MVC triad ● Contain actions for the triad ● Injected with references to the model and view
  • 20. Sample Griffon Controller File class HelloController { // these will be injected by Griffon def model def view // void mvcGroupInit(Map args) { // // this method is called after model and view are injected // } // void mvcGroupDestroy() { // // this method is called when the group is destroyed // }
  • 21. Griffon Plugins ● Extend app functionality at runtime or compile-time ● Can be as simple as adding a couple jars... ● Or as complex as creating a custom builder to use them ● Common areas: ○ UI Toolkits ○ Dependency Injection ○ Persistence
  • 22. Code (From inside a Griffon app directory) griffon list-plugins griffon lP griffon plugin-info <name of plugin>
  • 23. Creating A ToDo Application
  • 24. Code griffon create-app TodoApp <wait... wait... wait...> griffon install-plugin swingx-builder griffon install-plugin swingxtras-builder griffon install-plugin validation
  • 25. Code (/src/main/todoapp/...) class TodoItem { String todoText Date dueDate List <String>tags Boolean isDone Boolean isSaved public tagsToString() { Arrays.sort(tags) tags.join(',') } }
  • 26. Code (/griffon-app/models/todoapp/.) import groovy.beans.Bindable class TodoModel { @Bindable String todoText @Bindable Date dueDate @Bindable tagsText List <TodoItem> todos }
  • 27. Code (griffon-app/views/todoapp/...) size: [640,480], locationByPlatform:true, layout: new MigLayout()) { // Add Todo field jxtextField(id:'todoField', columns:45, text:bind(target:model, 'todoText'), constraints:'w 90%') promptSupport(todoField, prompt: "Add Todo, type here") button(id:'btnAdd', text:'Add', constraints:'w 10%, wrap') }
  • 29. Code (griffon-app/views/todoapp/...) // More options (date, tags, etc) jxtaskPane(title:'More Options', constraints: 'w 100%, spanx 2, wrap', layout: new MigLayout()) { label(text:'Due Date:', constraints:'wrap') jxdatePicker(id:'datePicker', date:bind(target:model,'dueDate'), constraints:'wrap') label(text:'Tags', constraints:'wrap') textField(id:'tagsField', columns:40, text:bind(target:model, 'tagsText')) promptSupport(tagsField, prompt:'Enter tags comma separated') }
  • 32. ... devs are just coding it badly
  • 33. Don't do this! JButton b = new JButton("Run query"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runQueries(); } });
  • 34. Threading in Swing ● All updates to the UI must happen on the single Event Dispatcher Thread(EDT) ● Nothing else should be executed on the EDT* ● Bad dev starts long running task, UI locks up until it is done ● SwingUtilities provides the following functions: ○ isEventDispatchThread() ○ invokeLater(Runnable), invoke Runnable when convenient ○ invokeAndWait(Runnable) invoke when convenient and wait for completion
  • 35. (Swing) Threading in Griffon ● Encapsulates SwingUtilities and simple threading ● Adds closure for running a task outside the EDT ● Available closures: ○ doLater { ... } ==> SwingUtilities.doLater ○ edt{ ...} ==> SwingUtilities.invokeAndWait ○ doOutside{..} ==> Spawns new Thread if inside EDT ● Griffon 0.9.2+ encloses controller actions with doOutside by default (can be turned off)
  • 36. Code (griffon-app/controllers/...) def load = { doOutside { def todos = model.derby.all() todos.each { def todo = TodoItem.fromMap(it) model.todos.add(todo) } } }
  • 37. Adding a table of todo items
  • 38. The old way ... ● A very brittle TableModel ● Hard to update and sort items ● Hard to map between POJOs and rows
  • 39. Code (SwingPad) import javax.swing.table.DefaultTableModel def a = new DefaultTableModel(['A','B','C'] as String[], 0) a.addRow(1,2,3) a.addRow(4,5,6) a.addRow(7,8,9) scrollPane { jxtable(model:a) }
  • 40. Code (griffon-app/views/todoapp/...) ... jxtitledPanel(title:'Tasks') { scrollPane { jxtable(id:'table', model:model.todoTableModel) } }
  • 41. GlazedLists ● Easy data model management for: ○ JComboBox, ○ JList ○ JTable ● Provides easy dynamic sorting and filtering ● Supports both SWT and Swing ● Supports concurrency ● Link: http://glazedlists.com
  • 42. BasicEventList ● Compatible with ArrayList and Vector ● Stores the items for your List or Table ● Parameterized around POJO BasicEventList todos = new BasicEventList<TodoItem>() ● Adds listeners for changes in the list
  • 43. BasicEvent<Widget>Model ● Receives changes from BasicEventList and pushes them to the widget ● BasicEventListModel and BasicEventComboModel take only a BasicEventList (POJOs to display) as a parameter ● JTables require a bit more definition
  • 44. TableFormat ● Interface that defines how the table is displayed in the GUI ● By default is not editable after initialization ● Required functions: ○ getColumnCount() ○ getColumnName(int) ○ getColumnValue(obj, int)
  • 45. WritableTableFormat ● Interface allowing editing of fields ● Can set granular edit policy with isEditable ● Uses default field editor (usually a JTextField) ● Required functions: ○ isEditable(obj, column) ○ setColumnValue(obj, value, column)
  • 46. AdvancedTableFormat ● Interface that allows custom cell renderers For example: DatePickers, Check boxes, Sliders, etc. ● JTables set policies on how to render a cell with a certain class type ● JXTables do sorting and filtering so a separate comparator is not needed ● Required functions: ○ getColumnClass(int) ○ getColumnComparator(int)
  • 47. Adding a bit of Swing glue: Table Editors and Renderers
  • 48. TableEditor vs TableRenderers ● Any Swing component can be an editor or renderer ● TableEditors show when that cell is being edited ● TableRenderers appear in all other cases ● Can be mixed an matched For example: a default renderer but a specialized renderer
  • 49. Default TableRenderers Class Renderer Component Boolean* JCheckBox* Number JLabel, right-aligned Double, Float JLabel, right-aligned with coersion to String using NumberFormat Date JLabel, with coersion to String using DateFormat Object JLabel with object's toString() value
  • 50. Code (src/main/groovy) class CheckBoxRenderer extends JCheckBox implements TableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { setForeground(table.getSelectionForeground()) setBackground(table.getSelectionBackground()) } else { setForeground(table.getForeground()) setBackground(table.getBackground()) } setSelected(value) return this } }
  • 51. Code (src/main/groovy) class DatePickerEditor extends AbstractCellEditor implements TableCellEditor { def component = new JXDatePicker() public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { component.setDate(value) return component } public Object getCellEditorValue() { return component.getDate() } }
  • 52. Code (griffon-app/controllers/...) // setup renderers and editors view.table.setDefaultRenderer(Boolean.class, new CheckBoxRenderer()) view.table.setDefaultEditor(Boolean.class, new DefaultCellEditor(new JCheckBox())) view.table.setDefaultEditor(Date.class, new DatePickerEditor())
  • 53. Code (griffon-app/controllers/...) // table model listener model.todoTableModel.addTableModelListener([tableChanged: {evt -> def i = evt.getFirstRow() def j = evt.getLastRow() if (i == j && evt.getType() == TableModelEvent.UPDATE) { // do something with the update date } }] as TableModelListener)
  • 54. Code (griffon-app/controllers/...) def deleteCompleted = { def lock = model.todos.getReadWriteLock().writeLock() lock.lock() def list = model.todos.findAll{item -> item.isDone == true } list.each { item -> model.derby.remove(item.id) model.todos.remove(item) } lock.unlock() }
  • 57. Introducing Deckchair ● Modeled after Lawnchair, a lightweight JSON store (JS) ● Written in Groovy ● Uses an adapter-implementation model for persistence Derby is the only implemented backend for Deckchair ● Provides more flexibility than direct use of backends ● Link: http://github.com/jwill/deckchair
  • 58. Deckchair API ● save, saves a single object ● get, retreives an object ● each, executes code for every item in the result set ● find, finds objects using a closure ● all, returns all objects in the set ● nuke, destroys all objects in the set ● remove, destroys a single object
  • 59. Deckchair Derby Internals ● Creates a table with: ○ id, 36-character VARCHAR ○ timestamp, BIGINT ○ value, LONG VARCHAR (about 32,000 characters) ● Objects are serialized to JSON strings on insertion ● Only the uniqueness of the id field is enforced ● Good for small amounts of data and demos ● Good for data models that aren't exactly pinned down yet
  • 60. Code // from model def derby = new Deckchair([name:'todos', adaptor:'derby']) //loading todos def todos = model.derby.all() // save function with optional closure to print status after completion model.derby.save(changedTodo.toMap(), {obj -> println obj; println "saved todo"} )
  • 62. GValidation Plugin ● Provides Grails style validation and messages ● Uses a Grails-like DSL ● Supports custom constraints in addition to built-in types ● Provides visual cues for incorrect data ● Can internationalize error messages with the Griffon i18n plugin
  • 63. Code (griffon-app/models/...) package todo import jwill.deckchair.* import groovy.beans.Bindable //... @Validatable class TodoModel { @Bindable String todoText @Bindable Date dueDate @Bindable tagsText //... static constraints = { todoText(blank:false) dueDate(nullable:true) tagsText(blank:true) } }
  • 64. Supported Validators ● blank ● min ● creditCard ● minSize ● email ● notEqual ● inetAddress ● nullable ● inList ● range ● matches ● size ● max ● url
  • 65. Validation an object def addItem = { if (model.validate()) { // save file } catch(Exception ex) { } } else { model.errors.each{error -> println error } } }
  • 66. Showing a error component jxtextField( id:'todoField', columns:45, text:bind(target:model, 'todoText'), constraints:'w 90%', errorRenderer:'for: todoText, styles: [highlight, popup]' )
  • 69. There once was a java.net project called EasyPrint
  • 70. It was a casualty to the Java. net/Kenai conversion :(
  • 72. Code (griffon-app/controllers/...) def builder = new MarkupBuilder(writer) builder.html { head{ title('My Todo List') } body { h2("My Todo List") br {} table (width:'90%', border:1, 'border-spacing':0){ tr { td('Completed'); td('Description'); td('Due Date'); td('Tags') } model.todos.each { item -> tr { if (item.isDone) { td('Done') } else { td() } td(item.todoText) td(item.dueDate) td(item.tagsToString()) } } } } }
  • 73. Code (griffon-app/controllers/...) def createPDF = { createHTML() def file = File.createTempFile("todos","txt"); file.write(writer.toString()) def docBuilder = DocumentBuilderFactory.newInstance(). newDocumentBuilder() def doc = docBuilder.parse(file) def renderer = new ITextRenderer() renderer.setDocument(doc, null) def outputFile = "todos.pdf" def os = new FileOutputStream(outputFile) renderer.layout(); renderer.createPDF(os); os.close() edt { JOptionPane.showMessageDialog(null, "PDF created.") } }