15.3 Externalizing Views - Reference Documentation
Authors: Andres Almiray
Version: 1.2.0
15.3 Externalizing Views
Groovy is the default language/format for writing Views, however there might be times where you would rather use a different format for describing a View. It might be the case that you have a legacy View (plain Java code) that you would like to plugin into Griffon. Here are a few tips to get the job done.15.3.1 NetBeans Matisse
NetBeans comes with a visual designer named Matisse which is quite popular among a good number of developers. Matisse views are usually defined by a Java class. Most of the times all UI widgets are exposed as fields on the Java class. Based with this information Griffon can generate a View script that is backed by this particular Java class. Follow these steps to reuse a Matisse view.#1 Place the Matisse View in your application
If you have access to the View's source code then please it somewhere in the application's source tree. A matching package to the traget MVC group insrc/main
is what is preferred. However, if the View is distributed in byte code form the make sure to place the jar that contains the View inside the application's lib
directory. Alternatively you can use the Dependency DSL if the jar is available from a jar file repository (such as Maven or Ivy). Lastly, make sure that you have added the jar that contains GroupLayout
, Matisse's work horse. this is easily accomplished by adding the following confuration in griffon-app/conf/BuildConfig.groovy
griffon.project.dependency.resolution = { repositories { // enable this option in an existing 'repositories' block mavenCentral() } dependencies { // add this to an existing 'dependencies' block compile 'org.swinglabs:swing-layout:1.0.3' } }
#2 Convert the View into a Script
Griffon includes a script commmand target that can read a Matisse View and generate a Groovy View Script from it:generate-view-script
. Execute the command by specifying the name of the Java class that defines the Matisse View, like thisgriffon generate-view-script sample.LoginDialog
griffon-app/views/sample/LoginDialogView.groovy
with the following contents// create instance of view object widget(new LoginDialog(), id:'loginDialog')noparent { // javax.swing.JTextField usernameField declared in LoginDialog bean(loginDialog.usernameField, id:'usernameField') // javax.swing.JPasswordField passwordField declared in LoginDialog bean(loginDialog.passwordField, id:'passwordField') // javax.swing.JButton okButton declared in LoginDialog bean(loginDialog.okButton, id:'okButton') // javax.swing.JButton cancelButton declared in LoginDialog bean(loginDialog.cancelButton, id:'cancelButton') } return loginDialog
#3 Tweak the generated View
From here on you can update the generated View as you see fit, for example by adding bindings to each field and actions to the buttonswidget(new LoginDialog(mainFrame, true), id:'loginDialog') noparent { bean(loginDialog.usernameField, id:'usernameField', text: bind(target: model, 'username')) bean(loginDialog.passwordField, id:'passwordField', text: bind(target: model, 'password')) bean(loginDialog.okButton, id:'okButton', actionPerformed: controller.loginOk) bean(loginDialog.cancelButton, id:'cancelButton', actionPerformed: controller.loginCancel) } return loginDialog
15.3.2 Abeille Forms Designer
Another interesting choice is Abeille Forms, which is supported via a Builder and a plugin. Abeille Forms includes a visual designer that arranges the widgets with either JGoodies FormLayout or the JDK's GridBagLayout. Integrating these kind of views is a bit easier than the previous ones, as Abeille Forms views are usually distributed in either XML or a binary format. The plugin provides a View node that is capable of reading both formats. Follow these steps to setup a View of this type.#1 Install the Abeille Forms plugin
As with any oher plugin, just call theinstall-plugin
command with the name of the plugingriffon install-plugin abeilleform-builder
#2 Place the form definition in your source code
If you have direct access to the files generated by Abeille's designer then place them somewhere undergriffon-app/resources
. Otherwise if the files are packaged in a jar, place the jar in your application's lib
directory. Alternatively you can use the Dependency DSL if the jar is available from a jar file repository (such as Maven or Ivy).#3 Use the formPanel node
As a final step you just need to use theformPanel
node in a regular Groovy View script. All of the form's elements will be exposed to the Script, which means you can tweak their bindings and actions too, like thisdialog(owner: mainFrame, id: "loginDialog", resizable: false, pack: true, locationByPlatform:true, iconImage: imageIcon('/griffon-icon-48x48.png').image, iconImages: [imageIcon('/griffon-icon-48x48.png').image, imageIcon('/griffon-icon-32x32.png').image, imageIcon('/griffon-icon-16x16.png').image]) { formPanel('login.xml') noparent { bean(model, username: bind{ usernameField.text }) bean(model, password: bind{ passwordField.text }) bean(okButton, actionPerformed: controller.loginOk) bean(cancelButton, actionPerformed: controller.loginCancel) } }
15.3.3 XML
Yet another option to externalize a View is a custom XML format that closely ressembles the code that you can find in a Groovy View script. Why XML you ask? Well because it is a ver popular format choice still, some developers prefer writing declarative programming with it. This option is recommended to be paired with Java views, just because if you're writing a Groovy View it makes more sense to use Groovy to write the whole instead. Follow these steps to get it done.#1 Change the Java View class
A typical Java View class will extend from AbstractGriffonView. This super class defines a method namedbuildViewFromXml()
that takes a Map as its sole argument. This map should contain all variables that the builder may require to wire the View, such as 'app', 'controller' and 'model' for example.package sample;import java.util.Map;import org.codehaus.griffon.runtime.core.AbstractGriffonView;public class SampleView extends AbstractGriffonView { private SampleController controller; private SampleModel model; public void setController(SampleController controller) { this.controller = controller; } public void setModel(SampleModel model) { this.model = model; } public void mvcGroupInit(Map<String, Object> args) { buildViewFromXml(args); } }
#2 Define the XML view
ThebuildViewFromXml()
method expects an XML file whose name matches the name of the class from where it's called, in this case it should be SampleViw.xml
. Make sure to place the following contents in griffon-app/resources/sample/SampleView.xml
<application title="app.config.application.title" pack="true"> <actions> <action id="'clickAction'" name="'Click'" closure="{controller.click(it)}"/> </actions> <gridLayout cols="1" rows="3"/> <textField id="'input'" columns="20" text="bind('value', target: model)"/> <textField id="'output'" columns="20" text="bind{model.value}" editable="false"/> <button action="clickAction"/> </application>
application(title: app.config.application.title, pack: true) { actions { action(id: 'clickAction', name: 'Click', closure: {controller.click(it)}) } gridLayout(cols: 1, rows: 3) textField(id: 'input', text: bind('value', target: model), columns: 20) textField(id: 'output', text: bind{model.value}, columns: 20, editable: false) button(action: clickAction) }