Динамическая передача параметров слушателям событий AS3 - PullRequest
2 голосов
/ 28 сентября 2011

У меня есть сетка кнопок 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 ]

1 голос
/ 03 декабря 2012

Используя переменную из внешней области видимости внутри анонимной функции, вы получаете большие проблемы с замыканиями и утечкой памяти: position используется в function(e:MouseEvent), но он был создан в function Grid(), поэтому он будет подчиняться function Grid() изменения. И вы имеете дело с 256 function(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
    }
  }
}

Поскольку вы добавляете 256 прослушивателей, вы должны хранить каждую в разных переменных (для нее был составлен список свойств functions[position]), поэтому вы можете безопасно удалить каждого из них позже для освобождения памяти так же, как вы их добавили.

Это было разработано из этого ответа .

1 голос
/ 28 сентября 2011

есть некоторые другие опции ...

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

это, по сути, то, что вы хотели сделать, но это будет работать, поскольку переменная position не меняется.В вашем коде position меняется каждый раз, когда выполняется цикл, затем, когда вы запускаете функцию слушателя, она использует последнее значение, которое было назначено position, поэтому вы получаете 255 для всех из них.Дайте мне знать, если это не имеет смысла ...

1 голос
/ 28 сентября 2011

Вы можете добавить имя к этой кнопке, например, 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 голосов
/ 28 сентября 2011

Я попробовал это, и это работало нормально .... т.е. нажатие на разные текстовые поля отслеживало различное значение.Идея состоит в том, чтобы создать новую ссылку на 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 голосов
/ 28 сентября 2011

Вы можете получить значения i и j из того же выражения, которое используется для назначения значений x и y кнопкам.Например:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...