Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>In this tutorial you will learn how to:</p> <ul> <li>use custom widgets with SwingBuilder,</li> <li>implement observer pattern (also known as subject-observer pattern) in Swing & Groovy,</li> <li>use action listners with SwingBuilder,</li> <li>build simple currency converter <img class="emoticon emoticon-smile" data-emoticon-name="smile" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/smile.png" alt="(smile)" title="(smile)" />.</li> </ul> <p>Swing introduced modified <strong>MVC</strong> pattern (for more details see <a href="http://java.sun.com/products/jfc/tsc/articles/architecture/">http://java.sun.com/products/jfc/tsc/articles/architecture/</a>). To update model I'll use <strong>observer pattern</strong> (if you're not familiar with it, see <a href="http://en.wikipedia.org/wiki/Observer_pattern">http://en.wikipedia.org/wiki/Observer_pattern</a>) which is directly supported in Java by <code>Observable</code> class and <code>Observer</code> interface in <code>java.util</code> package.</p> <p>For the example let's choose currency converter application from<strong>Java Generics and Collections</strong> book by <em>Maurice Naftalin</em> and <em>Philip Wadler</em> (<a href="http://www.oreilly.com/catalog/javagenerics/">http://www.oreilly.com/catalog/javagenerics/</a>) from chapter 9.5. It will show explicitly the benefits from using dynamic language like Groovy over static typed Java with generic observer pattern introduced in the book. If you would like to see implementation of generic observer pattern you can download examples from the book website and have a look.</p> <p>OK. Let's start with the model:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Model extends Observable { static CURRENCY = [ "USD", "EURO", "YEN" ] private Map rates = new HashMap() private long value void initialize(initialRates) { (0..CURRENCY.size() - 1).each { setRate(CURRENCY[it], initialRates[it]) } } // setting rate for currency void setRate(currency, f) { rates.put(currency, f); setChanged(); notifyObservers(currency); } // setting new value for currency void setValue(currency, double newValue) { value = Math.round(newValue / rates[currency]); setChanged(); notifyObservers(null); } // getter for value for particular currency def getValue(currency) { value * rates[currency] } } </pre></td></tr></table> <p>The converter model allows conversions over three different currencies. As you can see it extends Observable class to provide Model class observable behaviour (for more details see <a href="http://java.sun.com/javase/6/docs/api/java/util/Observable.html">java.util.Observable</a>).</p> <p>Now let's create two custom widgets for displaying rate and value. <br class="atl-forced-newline" /></p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class RateView extends JTextField implements Observer { private Model model; private currency; public void setModel(Model model) { this.model?.removeObserver(this) this.model = model model.addObserver(this) } public void update(Observable o, Object currency) { if (this.currency == currency) text = String.format("%15.2f", model.rates[currency]) } } class ValueView extends JTextField implements Observer { private Model model private currency public void setModel(Model model) { this.model?.removeObserver(this) this.model = model model.addObserver(this) } public void update(Observable o, Object currency) { if (currency == null || this.currency == currency) text = String.format("%15.2f", model.getValue(this.currency)); } } </pre></td></tr></table> <p>These classes extends <code>JTextField</code> to hold model and currency which is representing. They also implement <code>Observer</code> interface to be noticed when the model is changed. As you can see in update method there are not class casts required although it receives <code>Object</code>, because as dynamic nature of Groovy. Also in <code>setModel</code> method safe dereferencing is shown to protect from throwing <code>NullPointerException</code> when initially model is <code>null</code>.</p> <p>Now let's put it all together.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> swing = new SwingBuilder() model = new Model() frame = swing.frame(title: "Groovy SwingBuilder MVC Demo", layout: new GridLayout(4, 3), size: [300, 150], defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) { label("currency") label("rate") label("value") for (c in Model.CURRENCY) { label(c) widget(new RateView(), model: model, currency: c, action: swing.action(closure: { event -> event.source.model.setRate(event.source.currency, event.source.text.toDouble()); })) widget(new ValueView(), model: model, currency: c, action: swing.action(closure: {event -> event.source.model.setValue(event.source.currency, event.source.text.toDouble()); })) } } frame.show() model.initialize([1.0, 0.83, 0.56]); </pre></td></tr></table> <p>Frame is constructed by using <code>swing.frame()</code>. To frame there are provided <code>title</code>, <code>layout</code>, <code>defaultCloseOperation</code>, <code>size</code> properties. You can think of it like creating a new instance of <code>JFrame</code> and invoking methods <code>setTitle()</code>, <code>setLayout()</code>, <code>setDefaultCloseOperation()</code>, <code>setSize()</code>. Then 12 components are added to frame:</p> <ul> <li>JLabel components using label("label's text"),</li> <li>RateView components using widget() builder method and setting model, currency attributes,</li> <li>ValueView components in the same way like RateView.</li> </ul> <p>When new rate or value is entered all action listeners of that component are noticed with actionPerformed() method (<a href="http://java.sun.com/javase/6/docs/api/java/awt/event/ActionListener.html">java.awt.ActionListener</a>). To construct classes which implements ActionListner interface SwingBuilder provides <strong>action()</strong> builder method. One of this method's attributes is closure when we are able to provide our closure with application logic. The closure argument has ActionEvent type.</p> <p>Download the source code of the example: <a class="confluence-link unresolved" data-filename="SwingBuilderObserver.groovy" data-linked-resource-default-alias="SwingBuilderObserver.groovy" href="#">SwingBuilderObserver.groovy</a></p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced