Friday, April 06, 2007

Seeing Your Bindows Application This Way

Almost everything useful that you do with Bindows requires you to create parent child relationships with components. In other words, to create "controls" you always end up adding components to other components. After all, one of the main functionalities of the toolkit is to build visual controls that express behavior ( without behavior, your application is just another pretty face ).

For example, if you wanted to use a window component, you would instantiate BiWindow and then add it to the BiApplicationWindow. Like all components, BiWindow has a number of event listeners that provide behavior.

That got me thinking. Wouldn't it be nice to know the parent child relationships of a Bindows component or application? After all, that is one way of measuring how "big" your application is.

Or better yet, wouldn't it be nice to know the total number of events, the event types and their event handlers for application you're writing? Sometimes, your application is so big that it's tedious to go through the code, look at the events and then review the handlers.

So, I came up with a little reusable component called "AboutComponent" ( I thought about Bindow Eyes but people might think that this has something to do with a screen reader but it doesn't! ) that does just that --

  • Shows the parent child relationship in a component/application ( all components added to the parent )
  • Shows the total number of events that the component is listening for, the total number of events that each child is listening for and their event handlers

I've used it to look at out-of-the-box Bindows components. Here's one for BiWindow --

Here's another with the BiTabPane component with four tab pages --

Of course, it's really useful and fun to analyze your own components. Here's my imitation of the Yahoo! movie rater ( this is also their "Hover Invitation" UI Pattern; read more about it here ) --

What does this all mean?

The first tab shows the parent child relationships or how the components contain each other. It doesn't show inheritance or how the component extends/derives. So, if you're looking at a BiButton, what you won't see is anything pertaining to a BiLabel or BiComponent. Why? Well, those aren't added as children to BiButton.

So, if you wanted to see the whole structure tree, you'd need to check BiComponent and BiLabel separately.

But, the tree does show you all the children found in your component and does show you the "structure" of your design.

The second tab shows all the events that the components are listening for. You can click on each event and a list of the event handlers show up. You can use this to see if you've accidently added unnecessary event handlers. Instead of scanning possibly a large code base, this immediately tells you how many events ( and what they do ) and how they associate with the component.

Remember, adding an event listener doesn't replace/remove previous ones! There's always a symmetry involved. If you add an event, you have to remove it explicitly ( by calling the method removeEventListener() ) or implicitly ( by disposing of the component or calling the removeAll() method from the parent component ).

How do you use it?

All you do is instantiate the AboutComponent with the component that you're interested in. Here's one where we pass a BiWindow component as a parameter to AboutComponent --

Pretty simple.

Now, you might be wondering how all this works. It's pretty straightforward. First, you can find all the children in a component by calling the getChildren() method. It's available for all BiComponents. Then, for each child, you call getChildren(), and then repeat ( i.e. recurse ).

You do this a n times and build up your tree. Here's an example of how I built the component tree for the first tab --

For the second tab, we do the same sort of thing. Only now, we're also after the events. Every BiComponent is a BiEventTarget and so contains event listeners -- a multidimensional array hashed on the event name and a key.

With that information, you can access an object literal representing the event handler and the "this" object. In other words, the "_listener" object contains the arguments passed to the method addEventListener(evtName, fHandler, [obj]).

Here's how we do it in the method getEventHandlers() --

Of course, we're pretty dependent on whether Bindows continues to handle their event in the same way. In general, it's not a good idea to directly access internal data structures like _listeners.

It's this way today ( Bindows 2.55 ), but tomorrow, who knows.

I hope you find this useful. You can download everything here. Unzip them into the "samples" directory of your Bindows library. You'll see a directory called AboutComponent. All the HTML files there are examples. So, click and run!

You'll find AboutComponent defined in AboutComponent.js. I've tested this only on Bindows 2.55 ( Just an update. AboutComponent won't work in pre-2.5 versions of Bindows. I'll look into that and update AboutComponent in the next few days ).

If you want to see the four examples without downloading the ZIP file, you can go here --

Feel free to use and improve it. I'd love to hear your feedback. If you do use it, let people know where you got it.

Have fun!

No comments: