SlideShare uma empresa Scribd logo
1 de 74
Baixar para ler offline
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')

}
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')
}
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()
  }
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]'
)
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 ?

Mais conteúdo relacionado

Mais procurados

Mastering Maven 2.0 In 1 Hour V1.3
Mastering Maven 2.0 In 1 Hour V1.3Mastering Maven 2.0 In 1 Hour V1.3
Mastering Maven 2.0 In 1 Hour V1.3Matthew McCullough
 
Geb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosperGeb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosperEsther Lozano
 
Introducing Playwright's New Test Runner
Introducing Playwright's New Test RunnerIntroducing Playwright's New Test Runner
Introducing Playwright's New Test RunnerApplitools
 
Groovy in the Cloud
Groovy in the CloudGroovy in the Cloud
Groovy in the CloudDaniel Woods
 
Continuous integration with Git & CI Joe
Continuous integration with Git & CI JoeContinuous integration with Git & CI Joe
Continuous integration with Git & CI JoeShawn Price
 
Expressive Microservice Framework Blastoff
Expressive Microservice Framework BlastoffExpressive Microservice Framework Blastoff
Expressive Microservice Framework BlastoffAdam Culp
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is DockerNick Belhomme
 
Виталий Редько "React + Redux: performance & scalability"
Виталий Редько "React + Redux: performance & scalability"Виталий Редько "React + Redux: performance & scalability"
Виталий Редько "React + Redux: performance & scalability"Fwdays
 
Perl Continous Integration
Perl Continous IntegrationPerl Continous Integration
Perl Continous IntegrationMichael Peters
 
Laravel 4 package development
Laravel 4 package developmentLaravel 4 package development
Laravel 4 package developmentTihomir Opačić
 
PyCon Korea - Real World Graphene
PyCon Korea - Real World GraphenePyCon Korea - Real World Graphene
PyCon Korea - Real World GrapheneMarcin Gębala
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersKostas Saidis
 
Jedi Mind Tricks for Git
Jedi Mind Tricks for GitJedi Mind Tricks for Git
Jedi Mind Tricks for GitJan Krag
 
Zend Framework 1.8 workshop
Zend Framework 1.8 workshopZend Framework 1.8 workshop
Zend Framework 1.8 workshopNick Belhomme
 
Django Seminar 08/17/2013
Django Seminar 08/17/2013Django Seminar 08/17/2013
Django Seminar 08/17/2013Trinh Nguyen
 
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...chbornet
 

Mais procurados (20)

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

Destaque

Intro to HTML5 Game Programming
Intro to HTML5 Game ProgrammingIntro to HTML5 Game Programming
Intro to HTML5 Game ProgrammingJames Williams
 
Berlin 6 Open Access Conference: Dieter Imboden
Berlin 6 Open Access Conference: Dieter ImbodenBerlin 6 Open Access Conference: Dieter Imboden
Berlin 6 Open Access Conference: Dieter ImbodenCornelius Puschmann
 
Introduction to WebGL and Three.js
Introduction to WebGL and Three.jsIntroduction to WebGL and Three.js
Introduction to WebGL and Three.jsJames Williams
 

Destaque (7)

Intro to HTML5 Game Programming
Intro to HTML5 Game ProgrammingIntro to HTML5 Game Programming
Intro to HTML5 Game Programming
 
SVCC Intro to Grails
SVCC Intro to GrailsSVCC Intro to Grails
SVCC Intro to Grails
 
Quien Soy Yo
Quien Soy YoQuien Soy Yo
Quien Soy Yo
 
Vwff08
Vwff08Vwff08
Vwff08
 
Android Development
Android DevelopmentAndroid Development
Android Development
 
Berlin 6 Open Access Conference: Dieter Imboden
Berlin 6 Open Access Conference: Dieter ImbodenBerlin 6 Open Access Conference: Dieter Imboden
Berlin 6 Open Access Conference: Dieter Imboden
 
Introduction to WebGL and Three.js
Introduction to WebGL and Three.jsIntroduction to WebGL and Three.js
Introduction to WebGL and Three.js
 

Semelhante a Introduction to Griffon

Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
CodeMash - Building Rich Apps with Groovy SwingBuilder
CodeMash - Building Rich Apps with Groovy SwingBuilderCodeMash - Building Rich Apps with Groovy SwingBuilder
CodeMash - Building Rich Apps with Groovy SwingBuilderAndres Almiray
 
Annotation Processing
Annotation ProcessingAnnotation Processing
Annotation ProcessingJintin Lin
 
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin PovolnyDesign Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin PovolnyManageIQ
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentanistar sung
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andevMike Nakhimovich
 
Go 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoGo 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoRodolfo Carvalho
 
MEF Deep Dive by Piotr Wlodek
MEF Deep Dive by Piotr WlodekMEF Deep Dive by Piotr Wlodek
MEF Deep Dive by Piotr Wlodekinfusiondev
 
Mender.io | Develop embedded applications faster | Comparing C and Golang
Mender.io | Develop embedded applications faster | Comparing C and GolangMender.io | Develop embedded applications faster | Comparing C and Golang
Mender.io | Develop embedded applications faster | Comparing C and GolangMender.io
 
Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Joachim Baumann
 
step by step to write a gnome-shell extension
step by step to write a gnome-shell extension step by step to write a gnome-shell extension
step by step to write a gnome-shell extension Yuren Ju
 

Semelhante a Introduction to Griffon (20)

Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
Qt Workshop
Qt WorkshopQt Workshop
Qt Workshop
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
從零開始學 Android
從零開始學 Android從零開始學 Android
從零開始學 Android
 
CodeMash - Building Rich Apps with Groovy SwingBuilder
CodeMash - Building Rich Apps with Groovy SwingBuilderCodeMash - Building Rich Apps with Groovy SwingBuilder
CodeMash - Building Rich Apps with Groovy SwingBuilder
 
Gwt and Xtend
Gwt and XtendGwt and Xtend
Gwt and Xtend
 
Fragments anyone
Fragments anyone Fragments anyone
Fragments anyone
 
Annotation Processing
Annotation ProcessingAnnotation Processing
Annotation Processing
 
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin PovolnyDesign Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
 
Gephi Toolkit Tutorial
Gephi Toolkit TutorialGephi Toolkit Tutorial
Gephi Toolkit Tutorial
 
Flash develop presentation
Flash develop presentationFlash develop presentation
Flash develop presentation
 
Griffon Presentation
Griffon PresentationGriffon Presentation
Griffon Presentation
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app development
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Go 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoGo 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX Go
 
Gui
GuiGui
Gui
 
MEF Deep Dive by Piotr Wlodek
MEF Deep Dive by Piotr WlodekMEF Deep Dive by Piotr Wlodek
MEF Deep Dive by Piotr Wlodek
 
Mender.io | Develop embedded applications faster | Comparing C and Golang
Mender.io | Develop embedded applications faster | Comparing C and GolangMender.io | Develop embedded applications faster | Comparing C and Golang
Mender.io | Develop embedded applications faster | Comparing C and Golang
 
Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)
 
step by step to write a gnome-shell extension
step by step to write a gnome-shell extension step by step to write a gnome-shell extension
step by step to write a gnome-shell extension
 

Mais de James Williams

Griffon for the Enterprise
Griffon for the EnterpriseGriffon for the Enterprise
Griffon for the EnterpriseJames Williams
 
Game programming with Groovy
Game programming with GroovyGame programming with Groovy
Game programming with GroovyJames Williams
 
Java development with MongoDB
Java development with MongoDBJava development with MongoDB
Java development with MongoDBJames Williams
 
Porting legacy apps to Griffon
Porting legacy apps to GriffonPorting legacy apps to Griffon
Porting legacy apps to GriffonJames Williams
 
Using MongoDB With Groovy
Using MongoDB With GroovyUsing MongoDB With Groovy
Using MongoDB With GroovyJames Williams
 
Creating Voice Powered Apps with Ribbit
Creating Voice Powered Apps with RibbitCreating Voice Powered Apps with Ribbit
Creating Voice Powered Apps with RibbitJames Williams
 
Griffon: Swing just got fun again
Griffon: Swing just got fun againGriffon: Swing just got fun again
Griffon: Swing just got fun againJames Williams
 
Griffon: Swing just got fun again
Griffon: Swing just got fun againGriffon: Swing just got fun again
Griffon: Swing just got fun againJames Williams
 
Extending Groovys Swing User Interface in Builder to Build Richer Applications
Extending Groovys Swing User Interface in Builder to Build Richer ApplicationsExtending Groovys Swing User Interface in Builder to Build Richer Applications
Extending Groovys Swing User Interface in Builder to Build Richer ApplicationsJames Williams
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyJames Williams
 
Griffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java TechnologyGriffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java TechnologyJames Williams
 

Mais de James Williams (12)

Griffon for the Enterprise
Griffon for the EnterpriseGriffon for the Enterprise
Griffon for the Enterprise
 
Game programming with Groovy
Game programming with GroovyGame programming with Groovy
Game programming with Groovy
 
Java development with MongoDB
Java development with MongoDBJava development with MongoDB
Java development with MongoDB
 
Enterprise Griffon
Enterprise GriffonEnterprise Griffon
Enterprise Griffon
 
Porting legacy apps to Griffon
Porting legacy apps to GriffonPorting legacy apps to Griffon
Porting legacy apps to Griffon
 
Using MongoDB With Groovy
Using MongoDB With GroovyUsing MongoDB With Groovy
Using MongoDB With Groovy
 
Creating Voice Powered Apps with Ribbit
Creating Voice Powered Apps with RibbitCreating Voice Powered Apps with Ribbit
Creating Voice Powered Apps with Ribbit
 
Griffon: Swing just got fun again
Griffon: Swing just got fun againGriffon: Swing just got fun again
Griffon: Swing just got fun again
 
Griffon: Swing just got fun again
Griffon: Swing just got fun againGriffon: Swing just got fun again
Griffon: Swing just got fun again
 
Extending Groovys Swing User Interface in Builder to Build Richer Applications
Extending Groovys Swing User Interface in Builder to Build Richer ApplicationsExtending Groovys Swing User Interface in Builder to Build Richer Applications
Extending Groovys Swing User Interface in Builder to Build Richer Applications
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
 
Griffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java TechnologyGriffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java Technology
 

Último

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Último (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

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') }
  • 28.
  • 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') }
  • 30.
  • 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() }
  • 55.
  • 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]' )
  • 67.
  • 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.") } }