Создание функции внутри цикла (указатели?) - PullRequest
0 голосов
/ 27 мая 2010

Я пытаюсь создать простой цикл, который создает 50 кнопок, добавляет их на экран, а затем, когда кнопка нажата, она отслеживает это число. Я могу заставить его работать, делая вещи, которые я считаю хакерскими (например, используя расположение кнопок X / Y, чтобы определить его значение), но я бы предпочел просто сохранить одно значение в функции.

Сам код:

for (var a:int = 0; a < 5; a++) {
    for (var b:int = 0; b < 10; b++) {
        var n = (a * 10) + b + 1;
        var btt:SimpleButton = new BasicGameButton();
        btt.x = 20 + b * 50;
        btt.y = 50 + a * 80;
        addChild(btt);
        btt.addEventListener(MouseEvent.CLICK, function f() { trace(n); } );
    }
}

В данный момент, когда кнопка нажата, она просто выводит «50». Есть ли способ «заморозить» значение n при создании функции для этой функции? (BasicGameButton - это просто квадратная кнопка, созданная во флэш-библиотеке)

Большое спасибо.

Ответы [ 3 ]

0 голосов
/ 29 мая 2010

Я вижу, что ответ был выбран, но я не согласен с решением, хотя оно работает. Я бы не охарактеризовал это как недостаток AS3, поскольку это происходило бы так же с Javascript, также основанным на ECMAScript. В любом случае вы можете полностью избежать этой проблемы, просто создав свойство BasicGameButton, которое содержит значение n. Кроме того, вместо добавления прослушивателя для каждой кнопки, просто создайте отдельного прослушивателя в контейнере кнопок, который прослушивает щелчок мыши (щелчок мыши «всплывает» до родительского экранного объекта) и получает нажатую кнопку, используя цель события.

/* inside the loop */
btt.n = n;

/* parent listener you only have to create once */
buttonContainer.addEventListener(MouseEvent.CLICK, onClick);

function onClick(e:Event):void {
    trace(BasicGameButton(e.target).n);
}
0 голосов
/ 05 июня 2010

Я согласен с wpjmurray, что это вовсе не недостаток; скорее это результат работы контекста в EcmaScript.

Ваш обработчик кликов содержит неявную ссылку на переменную (n). Когда функция вызывается (вызывается щелчком), значение этой переменной изменилось. Это имеет смысл, когда вы думаете об этом таким образом.

Решение состоит в том, чтобы хранить значение на каждой итерации и каким-то образом связывать его с вашей кнопкой. Есть три хороших способа сделать это:

  1. Создать новое замыкание, которое само имеет неявную ссылку на другую переменную, значение которой устанавливается один раз, а затем остается в покое. Решение back2dos - это один из способов сделать это: makeFunction создает закрытие нового метода, которое имеет неявную ссылку на новую переменную (makeFunction 'n аргумент), которая не изменяется.
  2. Сохранить значение как свойство объекта. (Это то, что предложил wpjmurray, но вы не можете этого сделать.)
  3. Сохраните значение на карте и найдите его. Вы намекали на это, когда упоминали отображение координат X / Y на индекс. Тем не менее, ActionScript 3 предоставляет гораздо более… элегантный (: решение: Класс словаря ! Просто сопоставьте сам объект с индексом, а затем найдите его в обработчике.

Вот пример:

var dict:Dictionary = new Dictionary(true);
for (var a:int = 0; a < 5; a++) {
    for (var b:int = 0; b < 10; b++) {
        var n = (a * 10) + b + 1;
        var btt:SimpleButton = new BasicGameButton();
        btt.x = 20 + b * 50;
        btt.y = 50 + a * 80;
        addChild(btt);
        dict[btt] = n;
        btt.addEventListener(MouseEvent.CLICK, function f(event:MouseEvent) { trace(dict[event.currentTarget]); } );
    }
}

Из-за того, как работает область в EcmaScript, каждый созданный вами обработчик кликов содержит неявную ссылку на словарь, который вы можете использовать для поиска индекса. Теперь индекс отображается непосредственно на кнопку, без необходимости добавлять свойство или создавать новую функцию.

0 голосов
/ 27 мая 2010

это недостаток AS3, пришедший из заброшенного проекта ECMA-Script. AS3 основан на ... n ограничен самым внутренним телом функции, в котором он объявлен (таким образом, как если бы он был объявлен до цикла), хотя объявлено в самом внутреннем теле цикла вашего кода.

Вы можете сделать следующее:

var makeFunction:Function = function (n:int):Function {//this can of course also be a method
    return function (event:MouseEvent):void {
         trace(n);
    }
}

//in the loop body, use it like this:
btt.addEventListener(MouseEvent.CLICK, makeFunction(n));

В качестве примечания: Haxe не имеет этого недостатка.

...