Greg has posted 18 posts at DZone. You can read more from them at their website. View Full User Profile

Pivot: A Practical Example, Part 2 - Event Handling

07.07.2008
| 13656 views |
  • submit to reddit
This is the second in a series of five articles that walk through the implementation of a simple but practical Pivot application called Stock Tracker. The previous article discussed building a user interface using WTKX, Pivot's XML markup language. This section focuses on event handling. The next article will cover "web queries", Pivot's native means of communicating with remote data services. -- Greg Brown

WTKX files do not include any code - all logic in a Pivot application is implemented in Java. Most of this logic is executed in response to an "event" triggered by some external source such as user input or the completion of an asynchronous operation running in a background thread.

In general, a Pivot application will load its user interface and wire up event handlers in the startup() method of the main application class. This method, along with the shutdown(), suspend(), and resume() methods, is defined by the Application interface, which all Pivot applications must implement.

Loading the UI

The Application interface in the Stock Tracker demo is implemented by the StockTracker class. The code in this file is referred to throughout the course of this section. A snippet of code from StockTracker's startup() method is shown below:

ApplicationContext applicationContext = ApplicationContext.getInstance();

// Set the locale
String language = applicationContext.getProperty(LANGUAGE_PROPERTY_NAME);
locale = (language == null) ? Locale.getDefault() : new Locale(language);

// Set the application context title
ResourceBundle resourceBundle =
ResourceBundle.getBundle(StockTracker.class.getName(), locale);

applicationContext.setTitle(resourceBundle.getString("stockTracker"));

// Load the application's UI
ComponentLoader.initialize();
ComponentLoader componentLoader = new ComponentLoader(locale);

Component content = componentLoader.load("pivot/tutorials/stocktracker/stocktracker.wtkx",
getClass().getName());

This code does the following:

  • Gets a reference to the application context, a singleton class that provides access to a number of system-level features and properties

  • Retrieves the "langauge" argument that was provided to the application context when it was created - for desktop applications, this is a command-line argument; in the browser, it is either passed as a query string argument or as an applet parameter

  • Creates a locale instance corresponding to the language argument

  • Obtains a resource bundle for the current locale

  • Sets the application context title (reflected in the frame title when running in a desktop application context)

  • Creates a new component loader using the current locale

  • Loads the Stock Tracker user interface from stocktracker.wtkx

This last step creates the component hierarchy defined in the WTKX files and performs any necessary resource substitutions. The result is a new component instance that can be set as the content of a window and shown to the user.

Published at DZone with permission of its author, Greg Brown.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jacek Furmankiewicz replied on Mon, 2008/07/07 - 7:22am

The event listener logic is still pretty similar to Swing's. Maybe you could consider defining a straight Java method name in the XML file and hooking up the event listener automatically when the UI is loaded?

GTK+ libGlade (which is very similar conceptually to your solution) allows you to define method names in the XML file. If I remember correctly, it even handles finding the proper method name, regardless of the language (e.g. libGlade works with C/C++/Ruby/Python). They call it simply "signals" (I believe Qt has a similar approach). We can always learn something new and different from non-Java tools. :-)

See here for some info:
http://delirial.com/archives/tutorial-building-guis-for-ruby-programs-with-glade/

E.g. in the Glade XML file they define a signal for an event, e.g.:

Now, we need to add a signal (event) for quiting our program.

  • Go to the Signals tab in the Properties window.
  • Expand the GtkWidget node.
  • Select delete-event and type on_quit in the Handler column.

 and then on the Ruby side they just need to define a method called on_quit:

 

def on_quit(widget, arg0)
    puts "This is me leaving."
    Gtk.main_quit
end

You bypass the whole event listener paradigm this way and just hook up a 'signal' directly to a method (possibly with a pre-defined signature).

This would go some way towards differentiating Pivot from Swing and giving it some real edge as compared to its older brother.

I adopted the same approach in my SwingBuilder project, see the Wiki and maybe you can pinch some ideas for your solution:

http://code.google.com/p/javabuilders/wiki/JavaBuilderEventHandling

http://code.google.com/p/javabuilders/wiki/SwingBuilderEventHandlers

 

Greg Brown replied on Mon, 2008/07/07 - 8:03am in response to: Jacek Furmankiewicz

> Maybe you could consider defining a straight Java method name in the XML file and hooking up the event listener automatically when the UI is loaded?

There is definitely value in allowing a caller to do something like this. We don't necessarily want to embed code in WTKX, but including a method name would be OK. The question is - where would the method live? Event handlers are defined by interfaces which must be implemented by a class. We have considered allowing a caller to provide a handler class name in WTKX for a given event class (e.g. buttonPressListener="com.foo.MyButtonPressHandler") - the loader would instantiate the class and wire up the listener.

> This would go some way towards differentiating Pivot from Swing and giving it some real edge as compared to its older brother.

We actually like the way event handling works in Swing, for the most part. We eliminated the event objects and came up with what we think is a cleaner way to register for and fire events, but the basic listener model is pretty sound. What do you think the limitations are?

 

Jacek Furmankiewicz replied on Mon, 2008/07/07 - 8:14am in response to: Greg Brown

Just the amount of code that is required for clicking a button to call some Java-side method. 3-5 lines may not seem much, but once you add all the buttons you have in an app, it's a fair amount.

The 'signals' approach reduces it to a simple property value. And it's not really embedding code, think of it more of as defining a signal that can be used to map to a method when the file gets loaded.

The method would have to live in the object that is loading the layout file...I presume the loading engine has a way to get a reference to the object that called it?

Just a suggestion...if it doesn't fit with your philosophy of how the toolkit should work, that's fine. After all, it's your project :-)

Greg Brown replied on Mon, 2008/07/07 - 8:27am in response to: Jacek Furmankiewicz

> The method would have to live in the object that is loading the layout file...I presume the loading engine has a way to get a reference to the object that called it? 

At the moment, it doesn't - but that is an interesting idea. It could be a bit limiting, though, since handlers are often implemented as inner classes (anonymous or otherwise). The loading class would potentially have to implement a lot of interfaces, and the event handlers would be exposed as public methods (something we generally try to avoid, if possible).

> Just a suggestion...if it doesn't fit with your philosophy of how the toolkit should work, that's fine. After all, it's your project :-)

Understood. Thanks for the suggestion.  :-)

 

Jacek Furmankiewicz replied on Mon, 2008/07/07 - 8:38am in response to: Greg Brown

You're welcome.

I don't want to troll pushing my own project (which relies on YAML instead of XML), but just to give you a quick sample of how simple and productive signals can be:

 JButton(text=Save, onAction=save

would execute directly on the calling class without any other code needed:

private void save() {

   //save logic goes here

You could easily do something like this in your XML markup. Does it handle all scenarios? No. Does it handle 80% of the most common ones...probably yes. If you have a good solution that follows the 80/20 rule then it's a valuable addition IMHO.

Greg Brown replied on Mon, 2008/07/07 - 8:54am in response to: Jacek Furmankiewicz

> You could easily do something like this in your XML markup...If you have a good solution that follows the 80/20 rule then it's a valuable addition IMHO.

Agreed. The ability to hook up event handlers in WTKX will probably be a common request - something like your solution may well work for us.

 

Jacek Furmankiewicz replied on Mon, 2008/07/07 - 9:09am in response to: Greg Brown

Well, it's really a GTK+/Qt solution...I just pinched it from them and made it Java-specific. Gotta give credit where it's due.

P.S. The tricky part is passing event-specific arguments to the method (e.g. FocusListener vs ActionListener), since it may be needed sometimes. You can't always assume everyone will want a zero-arguments method. But if you manage to figure it out in the context of your project, it would be well worth it.

P.S.S. If I have the time (which unfortunately I don't) I may be able to write a PivotBuilder for you using the same reusable engine I have for the SwingBuilder, since I already handle most of these issues in a domain-generic way...ah, if only the day had 30 hours instead of 24.

P.S.S.S. Beg Mikael Grev to write a version of MigLayout for Pivot. :-)
MigLayout is worth its weight in gold.

Gregg Bolinger replied on Mon, 2008/07/07 - 8:22pm

I think the Pivot guys, Jacek, and the Groovy SwingBuilder guys all need to get together and pull something together that encompouses what you are all trying to do.  There a lot about Jacek's builder API I like and there is a lot about Pivot I like.  In the end, as long as you screw JavaFX into a has been, I'm cool with that. Oh wait, Sun's already doing a good of that. ;)

Jacek Furmankiewicz replied on Tue, 2008/07/08 - 2:51am in response to: Gregg Bolinger

Ah, if Java only supported embedded free-form text in .java files (no need for external XML or YAML files then). I hear something like this was coming in Java 7, but who knows what will make it in there since all the senior Sun engineers seem to be wasting their valuable time on JavaFX instead.

 It kills me that Java is missing such basic things as integrated data binding and properties (Beans Binding blows, I know...I've implemented support for it...you need more code to support bindable properties than the code they supposedly replace)...and yes JavaFX was able to get it added with Chris Oliver working on it in his spare time. To make it worse, the main guy in charge of new Java 7 features is moving away from properties:

http://blogs.sun.com/abuckley/en_US/entry/properties_in_java

Wake up, Alex...properties NEED to be added to Java, but instead of simple get/set replacements they need to have automatically integrated support for firePropertyChange(), so no one should ever need to call it manually. And binding should be integrated right into the language instead of being a clumsy separate library.

 Look how simple data binding is in Flex with their annotated variables (even less than properties):

[Bindable]
private var labelText:String = "This is a label";

<mx:Label text="{labelText}"/>

That's literally 1 line of code for an annotation ([Bindable]). In Java to support Beans Binding JSR 295 it's nearly 20 lines, since you need to add PropertyChangeSupport to every bindable class and property.

And Sun is wasting valuable limited resources on JavaFX and moving away from enhancing the core Java languag to keep up the competition? This is one of the most illogical things I've ever seen done by an IT corporation.

 

 

 

Greg Brown replied on Tue, 2008/07/08 - 8:49am in response to: Jacek Furmankiewicz

In Pivot, property binding like this is handled by the (pivot.collections) Map interface, which fires change events via the MapListener interface. This allows you to treat a statically typed Java object like a dynamically typed JavaScript object, as long as it implements Map. It requires some glue code to map property keys to getters and setters, but it works well. It's a little easier for Flex to support this since ActionScript objects are already dynamically typed.

In WTKX, you can achieve something similar to your Flex example using markup like this:

<Label textKey="labelText"/> 

The data binding section of the Quick Start tutorial talks about this in more detail. I'll be publishing it as an article on Javalobby soon:

https://pivot.dev.java.net/nonav/tutorials/stocktracker.data_binding.html

 

Jacek Furmankiewicz replied on Tue, 2008/07/08 - 9:09am in response to: Greg Brown

[quote=gbrown@vmware.com]It requires some glue code to map property keys to getters and setters[/quote]

That's exactly the issue I have in general...glue code needs to be added to each getter/setter and potentially even the class. I would love it just to work out-of-the-box without the need for extra glue code...I'm dreaming in technicolor, I know...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.