动态传递参数给AS3事件监听器

3

我有一个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);
            }
        }
    }
}

很遗憾,每次每个按钮调用监听器函数时,它使用i和j的最后两个值,这种情况下每个按钮返回255。

有什么建议吗?


1
你也可以使用闭包。请查看我对以下问题的回答:http://stackoverflow.com/questions/7396845/how-to-use-a-method-of-a-class-inside-a-callback-function-in-actionscript/7412402#7412402 - Vladimir Tsvetkov
除非你完全理解使用闭包的后果,否则不应该使用它们。 - The_asMan
5个回答

2

有一些其他的选择...

1 使用signals代替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) );

这段代码实际上实现了你想要的功能,但它能够工作是因为position变量没有改变。在你的代码中,position每次循环执行时都会发生变化,然后当你触发监听器函数时,它使用了最后一次赋值给position的值,这就是为什么所有值都是255的原因。如果这还不清楚,请告诉我...


1
你可以给这个按钮添加一个名称,例如 button.name = "button" + position;,在事件处理函数中,你可以从目标名称 (e.target.name) 中提取位置参数:
button.name = "button" + position;
button.addEventListener(MouseEvent.CLICK, buttonClick);

以及事件处理程序:

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

0

你可以从用于将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;
}

0

我尝试了这个方法,它很好用... 即点击不同的文本字段会跟踪不同的值。 这个想法是创建一个新的 pos:Number 引用,以便即使更新了 pos,闭包仍然指向旧的引用。

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;
        }
    }
}   

0
通过在匿名函数中使用外部作用域的变量,你已经遇到了闭包和内存泄漏的大问题:`position` 在 `function(e:MouseEvent)` 中被使用,但它是在 `function Grid()` 中创建的,因此它将遵循 `function Grid()` 的更改。而且你正在处理 256 个 `function(e:MouseEvent)`,这些函数已经添加但无法删除,会导致内存超载!
让我们以最简单的工作方式重新制作你的代码:
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
    }
  }
}

由于您正在添加256个侦听器,因此您必须将每个侦听器存储在不同的变量中(属性列表functions [position]就是为此而创建的),以便您可以安全地稍后删除每个侦听器以释放内存,就像您添加它们一样。

这是从this answer阐述的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接