Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
493 views
in Technique[技术] by (71.8m points)

actionscript 3 - To pass a parameter to event listener in AS3 the simple way... does it exist?

Expected / pseudo example:

stage.addEventListener(MouseEvent.CLICK, onClick.someWayToPassParameters(true, 123, 4.56, "string"));
function onClick(e:MouseEvent):void {
    trace("Received " + someWayToRetrieveParameters().b/i/n/s + ".");
}

For many years (3~4), on every website, forum, blog, wherever I searched, people tell me there's no simple way to do this. They usually suggest to:

  • Add the listener to a dynamic object, where you can set the value to an extra property and reference it (e.target.property / e.currentTarget.property) in the function.

    Not all classes are dynamic. It won't work on a Sprite, for example.

  • Extend the class of the object with a custom class to add property or to just make it dynamic.

    You'll have to create a whole new tweak class everytime.

  • Use an anonymous function as the event handler.

    There's no reference (and it's ugly). To remove the listener to free resources you're forced to do it from inside the function itself with arguments.callee.

  • Call another function, using the parameter, inside the event handler.

    And where in the event handler call does the parameter go?

  • Keep the event handler in the same scope as the parameter.

    Breach to a total semantic mess.

  • Encapsulate both event handler definition and addEventListener call in a function receiving the target and parameters.

    It can mix scopes, but it's a close one. You have to be careful, though.

...Among many other suggested workarounds.

All I want is just to pass an argument to the event handler so I can use it inside its function, just like any normal function!

Am I asking for too much?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Out of the box: it only takes 2 extra lines of elegant code to solve this ancient puzzle.

stage.addEventListener(MouseEvent.CLICK, onClick(true, 123, 4.56, "string"));
function onClick(b:Boolean, i:int, n:Number, s:String):Function {
  return function(e:MouseEvent):void {
    trace("Received " + b + ", " + i + ", " + n + " and " + s + ".");
  };
}

But most importantly, you will very likely need to remove the listener later to free resources, so +1 line to store it in a variable:

var functionOnClick:Function = onClick(true, 123, 4.56, "string");
stage.addEventListener(MouseEvent.CLICK, functionOnClick);
function onClick(b:Boolean, i:int, n:Number, s:String):Function {
  return function(e:MouseEvent):void {
    trace("Received " + b + ", " + i + ", " + n + " and " + s + ".");
  };
}

And you'll be able to remove it normally:

trace("Before: " + stage.hasEventListener(MouseEvent.CLICK));
stage.removeEventListener(MouseEvent.CLICK, functionOnClick);
trace("After: " + stage.hasEventListener(MouseEvent.CLICK));

Here's a more elaborated, dynamic example to prove its use:

function onClick(s:String):Function {
  return function(e:MouseEvent):void {
    trace("The square " + s + " at x = " + e.currentTarget.x + "px was clicked");
  };
}
var myFunctions:Array = new Array();
for (var i:int = 0; i < 10; i++) {
  myFunctions.push(onClick("#" + (i+1)));
}
for (i = 0; i < myFunctions.length; i++) {
  var square:Sprite = new Sprite();
  square.name = "sqr" + i;
  square.addChild(new Bitmap(new BitmapData(20, 20, false, 0)));
  square.x = 5 + 25 * i;
  square.addEventListener(MouseEvent.CLICK, myFunctions[i]);
  stage.addChild(square);
}

No properties through dynamic objects, no custom class, no loose functions, no scope overlap. Just what logic expects it to be: you're simply passing arguments to it.

And to remove every listener properly, you can do it like this later:

for (i = 0; i < myFunctions.length; i++) {
  square = stage.getChildByName("sqr" + i) as Sprite;
  trace("Before (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK));
  square.removeEventListener(MouseEvent.CLICK, myFunctions[i]);
  trace("After (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK));
  stage.removeChild(square);
}

IMHO this is the simplest yet most solid way to do it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...