Flash 将参数动态传递给事件侦听器AS3

Flash 将参数动态传递给事件侦听器AS3,flash,actionscript-3,actionscript,Flash,Actionscript 3,Actionscript,我有一个16x16的按钮网格,希望为每个按钮添加一个事件侦听器,这样当单击按钮时,它将返回其唯一的网格位置号(0-255之间的任何值); 到目前为止,我所拥有的: public static const GRID_SIZE:Number = 16; private var i:int; private var j:int; // Constructor public function Grid() { for (i = 0; i

我有一个16x16的按钮网格,希望为每个按钮添加一个事件侦听器,这样当单击按钮时,它将返回其唯一的网格位置号(0-255之间的任何值); 到目前为止,我所拥有的:

    public static const GRID_SIZE:Number = 16;
    private var i:int;
    private var j:int;

    // Constructor
    public function Grid()
    {
        for (i = 0; i < GRID_SIZE; i++)
        {
            for (j = 0; j < GRID_SIZE; j++)
            {
                // Creates new instance of GridButton, a custom class that extends SimpleButton
                var button:GridButton = new GridButton();

                // Arranges buttons into a grid
                button.x = (i + 1) * button.width;
                button.y = (j + 1) * button.height;

                // Create unique value for grid position
                var position:Number = i * GRID_SIZE + j;

                // Add listener to button, with position as extra param
                button.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) : void { buttonClick(e, position) } );

                // Adds button to Sprite
                addChild(button);
            }
        }
    }
}
public static const GRID\u SIZE:Number=16;
私有变量i:int;
私有变量j:int;
//建造师
公共功能网格()
{
对于(i=0;i
不幸的是,每次每个按钮调用listener函数时,它都使用最后两个值i和j,在本例中,每个按钮返回255


有什么建议吗?

您可以为此按钮添加一个名称,例如
button.name=“button”+positione.target.name
)提取位置参数:

和事件处理程序:

function buttonClick(e:MouseEvent) {
    var position:Number = Number(e.target.name.replace("button", ""));
    // ... do wathever you want with position parameter
}

可以从用于为按钮指定x和y值的同一表达式中获取i和j的值。例如:

button.addEventListener(MouseEvent.CLICK, clickHandler);

function clickHandler(e:MouseEvent) {
    var i:int   = (e.target.x / e.target.width) - 1;
    var j:int   = (e.target.y / e.target.height) - 1;

    var position:Number = i * GRID_SIZE + j;
}

还有一些其他的选择

1使用而不是flash事件侦听器,这将对其进行描述并提供更多详细信息。这也是一个快速入门的方法。我建议这样做的原因是,您可以设置一个信号来传递一个参数,因此不需要使用事件目标,因为它并不总是工作得最好

2使用函数工厂

// factory:
public function fooFactory($mc:GridButton):Function{
    var $f:Function = new Function($e:MouseEvent):void{
        trace($mc.x, $mc.y);
    }
    // you might want to consider adding these to a dictionary or array, so can remove the listeners to allow garbage collection
    return $f;
}


// then assign the function to the button like this
button.addEventListener(MouseEvent.CLICK, fooFactory(button) );

这基本上就是您想要做的,但它会起作用,因为
位置
var没有改变。在您的代码中,
位置
在每次执行循环时都会发生变化,然后当您启动侦听器函数时,它会使用上次分配的
位置
的值,这就是为什么所有这些值都会得到255。如果这不合理,请告诉我…

我试过这个,效果很好。单击不同的文本字段可以跟踪不同的值。 我们的想法是创建一个新的pos:Number引用,这样即使在更新pos之后,闭包仍然指向旧的pos:Number

package
{
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldType;

    public class AsDing extends Sprite
    {
        private static const GRID_SIZE:uint = 2;
        public function AsDing()
        {
            for(var i:uint=0; i<GRID_SIZE; i++)
            {
                for(var j:uint=0; j<GRID_SIZE; j++)
                {
                    var tf:TextField = new TextField();
                    var pos:Number = i*GRID_SIZE + j;
                    tf.text = pos.toString();
                    tf.type = TextFieldType.DYNAMIC;
                    tf.addEventListener(MouseEvent.MOUSE_DOWN, createMCHdlr(pos));
                    addChild(tf);
                    tf.x = i*100; tf.y = j*100;
                }
            }
        }

        private function createMCHdlr(pos:Number):Function
        {
            var ret:Function = function(evt:MouseEvent):void
            {
                trace('pos: ' + pos);
            };
            return ret;
        }
    }
}   
包
{
导入flash.display.Sprite;
导入flash.events.MouseEvent;
导入flash.text.TextField;
导入flash.text.TextFieldType;
公共类AsDing扩展了Sprite
{
私有静态常数网格大小:uint=2;
公共功能AsDing()
{

对于(var i:uint=0;i,通过在匿名函数中使用外部作用域的变量,您已经在闭包和内存泄漏方面遇到了很大的问题:
位置
用于
函数(e:MouseEvent)
,但它是在
函数网格()
中创建的,因此它将遵循
函数网格()
的更改。您正在处理添加但无法删除的256个
函数(e:MouseEvent)
s,导致内存过热

让我们以最简单的工作方式重新编写代码:

public static const GRID_SIZE:Number = 16;
private var i:int;
private var j:int;

public function Grid() {
  var functions:Object;

  for (i = 0; i < GRID_SIZE; i++) {
    for (j = 0; j < GRID_SIZE; j++) {
      var button:GridButton = new GridButton();
      button.x = (i + 1) * button.width;
      button.y = (j + 1) * button.height;
      var position:Number = i * GRID_SIZE + j;
      functions[position] = buttonClick(position);
      button.addEventListener(MouseEvent.CLICK, functions[position]);
      //button.removeEventListener(MouseEvent.CLICK, functions[position]);
      addChild(button);
    }
  }

  buttonClick(position:Number):Function {
    return function(e:MouseEvent):void {
      // Now you can use both unique "e" and "position" here for each button
    }
  }
}
public static const GRID\u SIZE:Number=16;
私有变量i:int;
私有变量j:int;
公共功能网格(){
var函数:对象;
对于(i=0;i
由于您要添加256个侦听器,因此必须将每个侦听器存储在不同的变量中(属性列表
函数[position]
就是为其制作的),以便以后可以安全地删除每个侦听器以释放内存,方法与添加它们的方法相同


这是从中详细阐述的。

您也可以使用闭包。请查看我对以下问题的回答:除非您完全理解使用闭包的后果,否则不应使用闭包。
public static const GRID_SIZE:Number = 16;
private var i:int;
private var j:int;

public function Grid() {
  var functions:Object;

  for (i = 0; i < GRID_SIZE; i++) {
    for (j = 0; j < GRID_SIZE; j++) {
      var button:GridButton = new GridButton();
      button.x = (i + 1) * button.width;
      button.y = (j + 1) * button.height;
      var position:Number = i * GRID_SIZE + j;
      functions[position] = buttonClick(position);
      button.addEventListener(MouseEvent.CLICK, functions[position]);
      //button.removeEventListener(MouseEvent.CLICK, functions[position]);
      addChild(button);
    }
  }

  buttonClick(position:Number):Function {
    return function(e:MouseEvent):void {
      // Now you can use both unique "e" and "position" here for each button
    }
  }
}