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

时间:2011-09-28 10:41:15

标签: 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 < 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.

有什么建议吗?

5 个答案:

答案 0 :(得分: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
}

答案 1 :(得分:1)

还有其他一些选择......

1 使用signals代替flash事件侦听器,here's a post描述它并提供更多详细信息。还有一个video tutorial可以帮助您快速入门。我建议这样做的原因是你可以设置一个信号来传递参数,所以你不需要使用事件目标,这并不总是最好的。

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 var没有改变。在你的代码中,position每次循环执行时都会发生变化,然后当你触发监听器函数时,它会使用position分配的最后一个值,这就是为什么你为所有这些值得到255的原因。如果这没有意义,请告诉我......

答案 2 :(得分:1)

通过在匿名函数中使用外部作用域中的变量,你已经遇到了关闭和内存泄漏的大问题: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]),因此您可以安全地删除每个以释放内存< / strong>与添加它们的方式相同。

这是从this answer详细阐述的。

答案 3 :(得分: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;
}

答案 4 :(得分: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;
        }
    }
}