Let's say I was using a custom Delegate with args...
but now with AS3 I need to do this
Code:
myBtn.addEventListener(Event.CLICK, someHandlerFunc)
function someHandlerFunc(){
someFunc(someArgs)
}
It's still work well... but it's kinda a pain to write an handler function for each btn (or whatever event sending object) I need. I mean.. if I have something like
Code:
function addPage(_nPage){
nPage += _nPage
}
and I got 3 button with "+1", "+2" and "+3" ... I'll do something like this ?
Code:
btn1.addEventListener(Event.CLICK, btn1Handler)
btn2.addEventListener(Event.CLICK, btn2Handler)
btn3.addEventListener(Event.CLICK, btn3Handler)
function btn1Handler(){
addPage(1);
}
function btn2Handler(){
addPage(2);
}
function btn3Handler(){
addPage(3);
}
is it me or it's kinda "ugly" ? I mean.. I could write 3 onRelease with Delegate in AS2... now I need 3 addEventListener with 3 function...
Based on your little code I've created a (realy simple) class which act like the old "arguments supported delegate"..without changing the scope
Code:
package {
import flash.events.Event;
public class CallArg{
public function CallArg(){
}
public static function create(method:Function, ... args):Function {
return function(event:Event):void{
method.apply(null, [event].concat(args));
}
}
}
}
I haven't tried the above class script, but looking at it I'd guess there are going to be some scope problems and some serious memory leaks over time...because the functions you're creating are going to be...I think...scoped to the CallArg class. They'll never get collected as garbage as long as an instance of that class is open, and you won't be able to get rid of the listeners. You'd need to weak-link your eventListeners and instantiate the WHOLE CLASS each time you wanted to create one event...not use the same class over and over to create multiple functions. Maybe I'm talking out my a**, but that's what it looks like to me.
Y'know what might be a nicer way, actually...well, depends what you want, but it's a little like the old AS2 method...
Make a dynamic class that extends Sprite, and use it for all your sprites. They you can assign whatever properties you want to that sprite, and pick them up when the event comes through... like
Code:
var z:DynamicSprite = new DynamicSprite();
z.args = new Array("some","stuff");
z.addEventListener(MouseEvent.ROLL_OVER,this.overFunction);
function overFunction(evt:MouseEvent) {
trace (evt.target.args[0]+evt.target.args[1]); //should read "somestuff"
}
Obviously, you could also just take advantage of MovieClips, but I'd think a dynamic sprite class would still be a lot faster. This would be the equivalent of the AS2 code:
There's yet one more way to do what you want and I guess it is most clean OOP one. You can create a class that extends the Event class, adding your own arguments straight to the event, so they are sent together with the event... 'cos that's what you're looking for, am I right?
I made myself an event class that informs that a property of animated object changed and it sends the changed value together with the event. I gave it a name AnimEvent (and it is actually working in one of the apps I create right now):
PHP Code:
package {
import flash.events.Event;
public class AnimEvent extends Event {
public static const ALPHA_CHANGE:String = "alpha_change";
public static const X_CHANGE:String = "x_change";
public static const Y_CHANGE:String = "y_change";
public static const SCALE_X_CHANGE:String = "scale_x_change";
public static const SCALE_Y_CHANGE:String = "scale_y_change";
public var value:Number;
public function AnimEvent(type:String, value:Number)
{
super(type);
this.value = value;
}
public override function clone():Event
{
return new AnimEvent(type, value);
}
public override function toString():String
{
return formatToString("AnimEvent", "type", "value", "bubbles", "cancelable", "eventPhase");
}
}
}
Then if you want to dispatch the event from inside the animated object, you go like that (let's say for alpha change):
PHP Code:
import AnimEvent;
var alphaEvent:AnimEvent=new AnimEvent(AnimEvent.ALPHA_CHANGE, value);
dispatchEvent(alphaEvent);
And the listener registering is just standard AS3 way:
PHP Code:
import AnimEvent;
function myListener(event:AnimEvent){
trace("alpha: ",event.value);
}
var myAnim:MyAnim=new MyAnim(); //some animation object that dispatches the event
myAnim.addEventListener(AnimEvent.ALPHA_CHANGE, myListener);
This way you can dispatch an event that you define yourself (you can use one of the static consts of the class to say what type of event it is) and you can send a value (or more values, if you need) with it.
Please say if it is what you were looking for
Last edited by ampo_webdesign; 05-31-2007 at 02:39 PM.
ampo_webdesign, if it's working in your code, then what you've described is what I want!
But being that I'm learning AS3 right now, I just need to research some of what's going on in your code, since I'm not familiar with some of the terms, such as super(), the clone() thing, why I see no call to these "override" functions and such....
But I'm sure that's outside the scope of this thread....
Yes, it is working, and as you put the class definition in a separate .as file and you forget about its existence, this way is actually very comfy. It simply adds to the standard syntax of AS3 events - so it is a seamless extension to the language. You just gain another event class, and use it like the standard Event class, MouseEvent class and all the other event classes
Here are some short answers to your follow-up questions:
1. All I do in this class is extending another class - Event (that is ready made in AS3). Extending is like saying: "my class is just like that class, only mine has some little things more..."
2. The super() is a method of invoking the original class that I'm about to extend - in the OOP language you name the one a 'superclass'. You can think of the super() method as creating the original class inside the new one. In this case we invoke the original Event class (it's constructor) and from that moment our new class has all the properties and methods of the Event class, so we don't need to build it from scratch. Actually the super() method would be called in my constructor (which is the AnimEvent function) even if I didn't put it there. But because I explains a lot, I call it explicitly.
3. The clone() is just a method of the Event class. Every time you define a new event class based on Event class, two methods have to be redefined: clone() and toString(). (I know it from the book .) So the clone() is just a function (or method) that I redefine.
4. The override syntax is just telling that you redefine a method. We are given a clone() method from Event class, but we don't want that one, because we build ourselves a new one, so we override the original with our version.
I hope this'll give you an easy start
Last edited by ampo_webdesign; 06-01-2007 at 02:20 AM.
I made myself an event class that informs that a property of animated object changed and it sends the changed value together with the event. I gave it a name AnimEvent (and it is actually working in one of the apps I create right now):
PHP Code:
package {
import flash.events.Event;
public class AnimEvent extends Event {
public static const ALPHA_CHANGE:String = "alpha_change";
public static const X_CHANGE:String = "x_change";
public static const Y_CHANGE:String = "y_change";
public static const SCALE_X_CHANGE:String = "scale_x_change";
public static const SCALE_Y_CHANGE:String = "scale_y_change";
public var value:Number;
public function AnimEvent(type:String, value:Number)
{
super(type);
this.value = value;
}
public override function clone():Event
{
return new AnimEvent(type, value);
}
public override function toString():String
{
return formatToString("AnimEvent", "type", "value", "bubbles", "cancelable", "eventPhase");
}
}
}
ampo_- i was thinking about this today...what if the desired returned property is not something that is a number? For example, the above event will always return a value that is a number, but what if the dispatch was sometimes a string? Do you have to write a different event extension to make this possible?
ampo_- i was thinking about this today...what if the desired returned property is not something that is a number? For example, the above event will always return a value that is a number, but what if the dispatch was sometimes a string? Do you have to write a different event extension to make this possible?
Yes, you have to write different event extension in that case. One of the ideas behind AS3 is strict typing of variables, properties and values. This strict typing makes the code safer and easier to debug (if you make a mistake with an assignment, the compiler can easier find and report it). So this approach is consistent with AS3 more-mature-programming ideology.
Please notice that the class I gave as an example is an event class that reports a change in an animated object's property - which is always a numer. So it is obvious that the value property of my event is of Number type.
If you need badly to override the typing, I guess you could use the * special type (or better said - no type), like that:
Code:
var value:*;
I've never tested it though, because it wouldn't be that AS3-consistent, would it? I consider the strict typing one of the advantages of AS3 and I'm after taking advantage of this advantage
New to AS 3.0 myself, but it occurs to me you could get around the typing issue by having ...(rest) syntax in the constructor for your new AnimEvent and updating the additional argument storage code accordingly.
G
New to AS 3.0 myself, but it occurs to me you could get around the typing issue by having ...(rest) syntax in the constructor for your new AnimEvent and updating the additional argument storage code accordingly.
G
I do not consider the typing an issue, I consider it an advantage. The beauty of AS3 is that everything is so strict and clean - I have an object which is prepared strictly for what I need in a specific field, and not for everything I could need on every field. Afterall, this is what objects are about, also in real life - if I have a bicycle, I cannot use it for slicing bread.
Thanks to strict typing my beloved compiler can help me find all my mistakes, it saves my time and frustration. Why would I want to break it or make it's work harder?
Easy tiger, I'm happy to OOP and in basic agreement with you.
My post is just an approach to get around something that _is_ occasionally required - especially for testing concepts. Sometimes, you just want throwaway code to see if something will work.
It's the same with database design where normalisation is a brilliant and very powerful concept that only an idiot would ignore. But, go too far and even the simplest update becomes a string of fifty or more SQL statements.
No worries, all good.
BTW, as an aside, there is a legitimate OOP example where ...(rest) is not only a workaround, but also the only way to achieve it in Flash (as far as I know - I'm happy to be educated).
Supposing you have multiple argument lists that you want to use for the same function. EG: A calculation that can either take [Point(),width,height], [x1,y1,x2,y2] or [MyShape()] as arguments but always does basically the same calculation.
You _could_ have multiple different functions ("myFuncXYWH()", "myFuncMyShape()", "myFuncPWH()") but imagine how unreadable and unmaintainable your code would then be (see also http://www.thc.org/root/phun/unmaintain.html for a laugh).
In Java (or similar), you can overload the function definitions with different argument signatures, but in AS3.0, there is no way to achieve this without ...(rest).
code:
private function myFunc(...(args)):Object {
var xin:Number;
var yin:Number;
var w:Number;
var h:Number;
if(args[0] is Point)) {
// assign vars
} else if(args[0] is MyShape)) {
// assign vars
} else {
// assign vars
}
return {tlc:new Point(xin,yin), brc:new Point(xin+w,yin+h), area:w*h};
}