As we discussed in our book, rather than follow
Flash MX v1 component's changeHandler route, we took a "listener"-centric
approach from the beginning, meaning that all our components communicate
events with other objects through an event/listener mechanism. Our
event/listener approach is similar to the approach embraced by the
Flash MX 2004 v2 component architecture.
If you are unfamiliar with listeners, we suggest that you look
over tutorials on www.ultrashock.com
in the Flash MX and Flash MX 2004 categories.
how to add listeners to a component
To register a listener with a component, for example, a listener
called myListener
with a button instance called myButton,
you would use the addListener()
method, as follows:
myButton.addListener(myListener);
All components automatically have this method because they derive
from a base class, we call FISBase,
which defines two important methods:
- addListener(inst)
- removeListener(inst)
In the addListener
example above, the listener is passed as the instance (inst).
For maximum flexibility, you can choose whether to pass in the instance
or simply the instance name (string), for example, myButton.addListener("myListener").
If you pass in the instance name, the listener is determined at
event notification time.
Why would you pass in the instance name rather than the instance?
If the instance is not defined yet when you want to place the addListener
call. Also, just because we're super-nice, you can specify absolute
(using _root, _global,
and _level) or relative
paths (using _parent)
in the string. For example, if your listener is located a few movie
clips above the current timeline, you could say myButton.addListener("_parent._parent.myListener").
If you are familiar with our components already you may realize
that it's not just because we're super nice (but it never hurts
to remind you of that, especially when we want you to pay us). The
real reason is for convenience. We like having the ability to specify
one listener in the component parameter panel for the component.
That way, when you drag the component onto the Stage, you can type
in the name of the listener instance (a string, coincidentally),
and then you don't have to programmatically add at least the first
listener.
what method receives the events in the listener?
Okay, so we've covered how to add listeners. Removing them is the
same, just with removeListener.
If you added the listener with an instance, you must remove it with
the instance. This is the same for instance name (strings), including
the relative or absolute path. Now that we've got the listener registered,
how does the component communicate with the listener come event
time?
In our book, we argued for the importance of centralizing event
handling, so we made all the components by default send their events
to a specific method of the listener. We named the method ieh,
for "internal event handler," since it was the event handler
responsible for coordinating subordinate (internal) interface elements.
This handler is defined as follows:
exampleListener.ieh =
function (m, v, w) { ... }
in which m is the
event message name, v
is an optional value to accompany the event, and w
is the component instance that sent the event.
While we still believe strongly in centralizing event handling,
we recognize that our choice of names was somewhat cryptic, and
others may not share our passion for centralizing things. Therefore,
in this component set, we offer alternative ways as well.
If you share our belief in event centralization but do not appreciate
our brevity in naming conventions, you can change the default event
handler. We have defined a property off the prototype
of FISBase (our base
listener class) called evHnd.
By default, it is set to ieh:
FISBaseClass.prototype.evHnd
= "ieh";
If you want to change the event handler name for all instances,
then you should change this value. Because of the way Flash MX instantiates
components, you could accomplish changing the handler name to handleEvent
by placing the following in your code
_root.FISBaseClass.prototype.evHnd
= "handleEvent";
If you are _root
phobic, such as Macromedia Central users, you can do either
one of two things. The first, probably the easiest, is to
find the FISComponents.fla
in the Flash directories and simply modify the FISBase
component (in Library > FIS Interface Components > Developer
Assets). The second option is to use an instance of a component
and navigate the __proto__
chain up to the FISBaseClass
prototype. This depends on which level the component you use
is on. For example, if the component is an FISButton,
it is 1 step removed from FISBase,
so you just need
myButton.__proto__.evHnd
= "handleEvent";
If you use a component that is a subclass
of another component that is subclass of FISBase,
then you need two __proto__'s
to get to the right level, and so on. |
You may also have figured out that you can change the event handler
on an instance-by-instance basis by simply modifying the evHnd
property for the instance. This does not change it for all components,
only the instance you set. For example,
myButton.evHnd = "handleEvent";
would change the event handler for the button instance alone, and
any other component would still communicate with the ieh
method (unless you change that too).
an alternative to centralized event handling
To allow you maximum flexibility, we also implemented a change
in FISBase to allow
event handling in a way similar to the way many people are used
to handling events, in methods such as "onClick"
for a button press.
Each component that generates an event allows the developer to
set an event name. For example, FISButton's
default event name is ButMsg.
By default then, if you have a listener object named myListener,
you now can write:
myListener.ButMsg = function
(v) { ... }
To make this look more natural, you could change the button's event
name in the component parameter panel or or programmatically, to
something like "onClick".
Then your handler would look like
myListener.onClick =
function (v) { ... }
Maybe that looks more familiar to the Flash listener crowd! Note,
however, that our all our button events come in on this method,
so you will receive notification on press, release, and release
outside the hit area (the value of v
will distinguish which event occurred). This is different from the
Flash events that have different event names. If you need this separate
event feature, add a feature request for it to our discussion
board!
| How does the listener mechanism handle a centralized
event handler versus an event specific handler? Basically, the
mechanism first checks the listener for a centralized handler
(e.g., ieh).
If it's found, then the centralized handler gets the message.
If it's not found, then the mechanism sends the message to a
method with the event name, if one exists. |
You will notice in the example code above that methods such as
onClick have only
one parameter, v,
but the ieh method had three: m,
v, and w.
If your event does not have a value, or you choose to ignore the
value, you do not need to leave it in the parameter list. The truth
is that the onClick
style methods also have a w
parameter, but we left it out of the example (it may or may not
be relevant to what the handler wants to do). The reason that m
is left off should be obvious--the onClick
is the event name, so there's no need to pass it in.
how do I tell components apart now during event handling?
If you use the second approach to event handling, and say you have
two buttons sending the same event to the one listener, you can
use the w parameter
to distinguish the components. For example,
myListener.onClick =
function (v, w) { ... }
Notice that if you want to see w's
value, you need to specify v,
even if the event does not have a value (it will pass in undefined).
|