Date post: | 27-Jan-2015 |
Category: |
Technology |
Upload: | james-williams |
View: | 107 times |
Download: | 1 times |
Porting your legacy apps to Griffon
James Williams@ecspike
Software Engineer, BT/Ribbit
Goals•The basics of Griffon•Griffon tenets•Respect the EDT's authority•SwingWorker is your friend•Embrace simpler layout managers•MVC does a codebase good•Go modular•Deploy, deploy, deploy!
What is Griffon?•desktop framework •inspired by Grails and the SAF•leverages Swing and Groovy•Apache 2 Licensed•extensible with plugins and addons
Griffon Tenets•Convention over Configuration•Don't Repeat Yourself•Pervasive MVC•Use Data Binding•Write Good Tests•Automate Tasks
Convention over Configuration
Griffon application structure
Core commands•griffon create-app•griffon run-app•griffon run-applet•griffon run-webstart•griffon package•griffon list-plugins•griffon install-plugin
Don't Repeat Yourself
Would you prefer this ...public class JavaFrame extends JFrame { public JavaFrame { setLayout(new GridLayout(3,1)); setTitle("JavaFrame"); setSize(100,100); add(new JLabel("One")); add(new JLabel("Two")); add(new JLabel("Three")); } public static void main(String [] args) { new JavaFrame().setVisible(true); }}
... or this?def swing = new SwingBuilder()
swing.frame(size:[100,100], title:'JavaFrame', layout:new GridLayout(3,1)) { label('One') label('Two') label('Three')}.show()
Griffon Builders•DSLs for UI components•allows nesting•takes parameters as a HashMap•can be mixed and matched
Supported UI toolkits•Swing/X•JIDE•MacWidgetsBuilder•Flamingo•SwingXtras•JavaFX
Respect the EDT
Respect the EDT•Event Dispatching thread•the cause of 94% of speed problems*
•only UI updates should run on it*•first-in/first out•Griffon EDT helpers•edt•doOutside/Later/Inside•withWorker
Swingworker•designed for long tasks•can periodically update the UI or notify processes outside the worker
•Swing Worker closures:•onInit•work•publish•onUpdate•onDone
Embrace simpler layout managers
What's the result of having to tweak the UI of a NB Matisse layout?
Pain.
MigLayout•row-column based layout manager•can replace most layout managers•uses constraints for positioning•can do relative positioning
MigLayoutimport net.miginfocom.swing.MigLayout application(title:'Griffon Weather', pack:true, size:[700,400], pack:true, locationByPlatform:true, layout:new MigLayout()) { label("Airport Code:") textField(id:'tf',columns:5, constraints:'spanx', actionPerformed: { controller.getJSON( 'http://ws.geonames.org/weatherIcaoJSON?ICAO=K'+tf.text?.toUpperCase()) } )
def createHorizontalBox = { fieldName, boundParam -> label(fieldName, constraints:"newline") label(id:fieldName.replace(' ','_')+'Label', foreground: java.awt.Color.BLUE, text: bind(source:model, sourceProperty:boundParam), constraints:'wrap' ) }
def createHorizontalBoxWithSuffix = { fieldName, boundParam, suffix -> label(fieldName, constraints:'newline') label(id:fieldName.replace(' ','_')+'Label', foreground: java.awt.Color.BLUE, text: bind(source:model, sourceProperty:boundParam, converter:{it + suffix}), constraints:"wrap, spanx") }
createHorizontalBox('Station: ', "stationName") createHorizontalBox('Clouds: ', "clouds") createHorizontalBoxWithSuffix('Wind Direction: ', "windDirection", " degrees") //truncated for brevity}
MigLayout
Pervasive MVC
MVC•Models•store data for the MVC Group•can mark properties as @Bindable
•Views•represent a single UI in your app•can be written in Groovy OR Java
•Controllers•the brains of the group
A sample modelimport groovy.beans.Bindable
class SampleModel { @Bindable String name def age def location}
A sample viewapplication(title:'Sample App', size:[320,480]){ label('Content goes here')}
A sample controllerclass SampleController { //injected by Griffon def model def view
void mvcGroupInit(Map args) { }
/* def action = {evt = null -> } */
Use Data Binding
Binding•automagically wraps properties•reduce the amount of code to update UIs•can move data in one or both directions
Binding exampleslabel(text:bind{model.name})label(text: bind(source:model, sourceProperty:'name'))textField(text: bind(target:model, targetProperty:'name'))
textField(text:bind(source:model, sourceProperty:'name', mutual:true))
MVC/Binding Demos
Write Good Tests
I should be I usually don't. :(
Automate Tasks
Go Modular
Modularity•plugins - compile-time extensions•addons - runtime extensions•~ 50 plugins/addons availiable•UI frameworks•Database•Testing frameworks•Other JVM languages
Deploy, Deploy, Deploy!
Deployment•Deploy to applet, webstart, or desktop with no code changes*•Installer plugin for OS specific pkgs
What if you can't move to Griffon?
•JavaBuilders•http://code.google.com/p/javabuilders
•Guts-Gui•http://kenai.com/projects/guts
•Netbeans Platform•http://platform.netbeans.org/
LinksBlog: http://jameswilliams.be/blogTwitter: @ecspikeGriffon: http://griffon.codehaus.org