2010-05-27 3 views
0

Я пытаюсь создать простой цикл, который создает 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 - это просто квадратная кнопка, созданная во флэш-библиотеке)

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

ответ

0

Это недостаток 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 не имеет этот недостаток.

Greetz
back2dos

+0

Это работает отлично. Большое спасибо, back2dos! – user352151

0

Я вижу, что ответ был выбран, но я не согласен с решением, хотя он работает. Я бы не охарактеризовал это как недостаток 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

BasicGameButton не был классом, а скорее экземпляром SimpleButton в флеш-библиотеке, и я надеялся избежать необходимости создавать класс специально для него. Таким образом, btt.n = n не работает (если только нет способа создать внешние переменные). Кроме того, фактическое использование кода Im немного сложнее, чем код, который я разместил выше, поэтому я действительно не могу использовать eventListener для родительского элемента, поскольку в фоновом режиме будет много кнопок и что-то не происходит. Тем не менее, я ценю вход. – user352151

0

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

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

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

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

Вот пример:

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, каждый клик обработчик, который вы создаете несет неявную ссылку на словарь, который вы можете использовать для просмотра индекса. Теперь индекс отображается непосредственно на кнопку, без необходимости добавлять свойство или создавать новую функцию.

Смежные вопросы