как передать параметр в слушатель
Достаточно быстро накидал, могут быть ошибки/неточности, опечатки, чего-то не хватать, постараюсь дополнить.
Часто бывает просто написать некую функцию paramFunc, которой передается номер кнопки, а не обьект собственно кнопки. Почти всё тут про, "как сопоставить обьекту (event.currentTarget) параметр".
Надо помнить, что addEventListener позволяет повесить сколько угодно слушателей, нижеприведённые методы, почти все - только один (обычно больше одного и не надо, но если забыть - могут быть ошибки). Тут всё скорее про мышиные события, с таймерами и др. могут быть особенности.
1. if/switch
Если кнопок мало и они создаются не динамически, то
public function listener(event:MouseEvent):void { if(event.currentTarget == myBtn1) { paramFunc(0); } else if(event.currentTarget == myBtn2) { paramFunc(1); } } public function listener(event:MouseEvent):void { switch(event.currentTarget) { case myBtn1: paramFunc(0); break; ... } } public function listener(event:MouseEvent):void { var myBtns:Array = [myBtn1, myBtn2, myBtn3]; for(var i:int = 0; i < myBtns.length; ++i) { if(event.currentTarget == myBtns[i]) { paramFunc(i); break; } } }
Достаточно универсальный способ, создание и работа с Dictionary единственное "лишнее" действие. На его основе можно написать даже свой addEventListener, в который передается параметр (может позже осилю).
Это класс, который обрабатывает только MouseEvent.CLICK.
Использовать - вместо obj.addEventListener(MouseEvent.CLICK, listener) писать
ClickClass.addClickListener(obj, listener, param);
public class ClickClass { public static var paramDict:Dictionary = new Dictionary(true); public static function addClickListener(obj:InteractiveObject, listener:Function, myParam:*, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void { paramDict[obj] =[listener, myParam]; obj.addEventListener(MouseEvent.CLICK, clickHandler, useCapture, priority, useWeakReference); } public static function myRemoveClickListener(obj:InteractiveObject, useCapture:Boolean = false):Boolean { if(paramDict[obj]) { obj.removeEventListener(MouseEvent.CLICK, obj, useCapture); delete paramDict[obj]; return true; } return false; } public static function clickHandler(event:MouseEvent):void { if(paramDict[event.currentTarget][0]) { paramDict[event.currentTarget][0](paramDict[event.currentTarget][1]); } } }
Если (почти) все обьекты класса заинтересованы в том, чтоб вызывать слушатель с параметром (напр. кнопки), то стоит сделать у класса новое поле, в котором будет храниться этот самый параметр. Хороший метод, но не всегда классу нужно и логично иметь такое поле. А иногда и собственного класса нет, просто спрайт. Но можно, конечно, сделать свой спрайт, с параметром, как ниже.
использование
myBtnButton.btnParam = i; myBtnButton.addEventListener(MouseEvent.CLICK, clickProxy); ... public function clickProxy(event:MouseEvent):void { paramFunc(event.currentTarget.btnParam); }
Анонимные функции - зло. Жрут память (с их убиранием есть проблемы, в примере), тормозят, если в них свалиться, то не узнать их имени, плохой стиль и многое другое. Пример (не используйте его, тут нельзя удалить эту функцию).
obj.addEventListener(MouseEvent.CLICK, function listener(ev:MouseEvent):void {paramFunc(i);});
5. custom event
Создается класс, который расширяет Event и в котором есть параметр. Только флэш не умеет вместо MouseEvent (или другого своего "родного") события использовать ваше, так что придётся в обработчике, созданном одним из вышеуказанных способов потом самому диспатчить событие.
Если вам более привычна событийная модель. Плюс на событие может быть навешено сколько угодно слушателей.
Всего комментариев 64
Комментарии
![]() ![]() |
|
Цитата:
не используйте его, тут нельзя удалить эту функцию
![]() Вашу проблему можно решить с помощью private function onMouseDown(ev:MouseEvent): void { ev.target.removeEventListener(ev.type, arguments.callee); } При этом пользоваться этим все так же не стоит. |
|
Обновил(-а) incoob 14.09.2010 в 19:31
|
![]() ![]() |
|
Блуд где то расписывал причины, по которым не стоит пользоваться замыканиями. Если это и решение - то одной из пяти, если не ошибаюсь.
|
![]() ![]() |
|
Цитата:
Собеседование он провалил
![]() |
![]() ![]() |
|
Я тоже ему так сказал )
|
![]() ![]() |
|
Нужно использовать только метод №5.
Т.е. при составлении конвенций кодирования для своего проекта я бы написал: для передачи параметра в событии используйте кастомное событие (в крайнем случае DataEvent или схожее), либо берите значение у диспетчера объекта. Всё остальное костыли. UPD 2incoob анонимных методов не бывает - это очень существенное противоречие. Метод ВСЕГДА принадлежит какому нибудь объекту (даже если это статичный метод - тогда он принадлежит глобальному классу). Анонимная функция АНОНИМНА - это не метод, это скорее, локальная переменная. |
|
Обновил(-а) Котяра 16.09.2010 в 23:21
|
![]() ![]() |
|
Дык нельзя использовать только метод №5, вот в чем его минус)
|
![]() ![]() |
|
Цитата:
Дык нельзя использовать только метод №5, вот в чем его минус)
- Чем лучше? - Чем БМВ. |
![]() ![]() |
|
Второй и третий тоже ниче так.
|
![]() ![]() |
|
Использую только #3 и #5. IMO остальное не нужно и вряд ли будет нужно при любом раскладе.
|
![]() ![]() |
|
любой костыль имеет право на жизнь, но костылём он от этого не перестаёт быть.
|
![]() ![]() |
|
Цитата:
что и замыкание есть места где можно использовать.
Приведи примеры, где оно хорошо впишется Действительно для подобного было бы гиморно создавть отдельные функции )) |
![]() ![]() |
|
2Blood: интересно, но непонятно ) Почему нельзя написать менеджер, ловящий ENTER_FRAME и вызывающий столько методов со столькими аргументами сколько нужно? Не вижу тут того, в чем замыкание "реально" оправдывает себя: по мне тут экономия времени разработки с 15 минут до 30 секунд, но в релиз версии проекта я бы себе такое не позволил )
И да, почему константа написана мелкими буквами? Конвенция на константы не распространяется на сложные типы в силу "нечестных констант"? |
|
Обновил(-а) Psycho Tiger 19.09.2010 в 23:11
|
![]() ![]() |
|
Цитата:
Зачем вообще такое может понадобится?
|
![]() ![]() |
|
Я не так выразился, пост поправил уже)
Я хотел сказать "Зачем такое может понадобится в таком исполнении" ) |
![]() ![]() |
|
Я не о том. )
Это и есть место, в котором замыкание оправдано? |
![]() ![]() |
|
Psycho Tiger, ну я его даже в этом случаи не использую. но вообще да.
|
![]() ![]() |
|
Друзья. Не забывайте зачем пишется код. Главное не чистота кода. Главное - продукт.
Если рентабельнее *****кодить - говонокодьте. |
![]() ![]() |
|
Мы 3+5 используем, вместе, не по-отдельности, чтобы типы поменьше приводить
Ибо не знаю как с тестами, но без них если что рефакторить - то типизация должна быть по-сильнее. |
![]() ![]() |
|
1 (редко) + не, не пять.
Я диспатчу обычные эвенты, которых полно во флешплеере, описываю их в ASDoc к классу - эмиттеру, а из класса-ресипиента, так как он наслышан о таргете, дергаю нужные геттеры. Но на самом деле тут разница (баланс) между POP и PUSH системой. Т.е. либо Вы передаете все в объекте события (a = event.iHasOneBillion), либо ресипиент тянет из объекта по событийной ссылке (a = event.target.gimmeOneBillion() ). |
|
Обновил(-а) dimarik 21.09.2010 в 00:12
|
![]() ![]() |
|
Цитата:
Друзья. Не забывайте зачем пишется код. Главное не чистота кода. Главное - продукт.
Если рентабельнее *****кодить - говонокодьте. ![]() А так, да - если низкий уровень абстракции справляется - то более высокий только проблем добавит. Но это разумный принцип разработки Цитата:
Psycho Tiger:
Блуд, я помню ты говорил что и замыкание есть места где можно использовать. Приведи примеры, где оно хорошо впишется. Мне на ум приходит разве что место где программа оканчивает работу на совсем с ошибкой: типа там уже без разницы, что и как - но и то идея не очень. public static function generateCallback(origin:Function, parameter:int):Function { return function(event:Event):void { origin(parameter, event); } } addEventListener(MouseEvent.CLICK, generateCallback(onClick, 1)); private function onClick(parameter:int, event:Event):void { // делаем что нужно } замедления работы с переменными тоже нет - она одна всего. Но такие фишки для haXe ещё как-то применимы - там все это дело типизировано - в as3 это только код запутывает |
|
Обновил(-а) expl 06.10.2010 в 00:44
|
![]() ![]() |
|
Ок, а как отпишетесь?
И откуда ифы 7-кратной вложенности вообще могут взяться? |
![]() ![]() |
|
Цитата:
Ок, а как отпишетесь?
Цитата:
И откуда ифы 7-кратной вложенности вообще могут взяться?
Но если не они, так дублирование кода без рефакторинга будет появлятся, и после правки очередного бага в 10 местах наступит "да пошло оно лесом, не убьет за рефакторинг меня никто", т.е. *****кодить дальше опять не получится ![]() |
|
Обновил(-а) expl 22.09.2010 в 22:52
|
![]() ![]() |
|
Тройная вложенность ифов у меня - крайняя редкость. Двойная - не часто. Я просто не понимаю, как можно добиться семикратной.
|
![]() ![]() |
|
5 кратная вложенность ифов с циклами - поверю. Речь шла конкретна об ифах.
Вроде в сортировке шелла 4-х кратная, кстати. Но это тоже с циклами. |
![]() ![]() |
|
7 просто красивое число)
можно было написать over 9000 уровней вложенности) |
![]() ![]() |
|
Можете не верить, но в нашей боевой версии я видел вложенность ифов и больше 7
Пример, правда тут алгоритм, а не логика, локика отрефакторена уже к сожалению: while ((!found) && (!noWay)) { ... outerLoop: for each(x in xs) { ... for (yString in newMaskX) { ... } for each(y in ys) { if (newMaskX[y] == wayLength - 1) { for (i = 0; i < 4; i++) // перебор по соседям заполненных в поисках пустой { ... if ((shiftedX == startX) && (shiftedY == startY)) { ... } if (getValue(shiftedX, shiftedY) == MaskCell.ROAD) { ... if (newLine == null || newLine[shiftedY] == null) { ... if (newLine == null) { newLine = []; newMask[shiftedX] = newLine; } newLine[shiftedY] = wayLength; } } if (noWay == true) { ... } } } } } } |
|
Обновил(-а) expl 24.09.2010 в 22:38
|
![]() ![]() |
|
часто такие контрукции получаются в результате "антирефакторинга" (вернее, всё же, рефакторинга в целях повышения производительности, но снижающего читабельность/реюзабельность), да и то очень постараться надо.
в коде выше как минимум можно было сократить в Цитата:
if (newLine == null || newLine[shiftedY] == null)
{ ... if (newLine == null) типа обрубаем циклы Цитата:
for each(y in ys)
{ doSmthWith(y); } вот: пример из моей практики (там as2, но и уровней больше (штук по 9 -12 встречается) |
|
Обновил(-а) Котяра 24.09.2010 в 23:37
|
![]() ![]() |
|
Цитата:
Не знаю насчет рефакторинга кода, может быть можно было сделать всё меньшим количеством ифов.
Цитата:
часто такие контрукции получаются в результате "антирефакторинга"
- он изолирован от всего остального и не правится уже несколько недель - нет "сложности вноса правок", потому что правок нет - код критичен к производительности - рефакторинг негативно на ней скажется Цитата:
используем стратегии и т.п.
вот: пример из моей практики (там as2, но и уровней больше (штук по 9 -12 встречается) Ну, блин, про это и речь - появляются ветки ифов - боремся с получившимися макаронами - низкокачественного кода не остается. Выовод - писать низкокачественный код не дешево! Что и требовалось доказать ![]() Иное дело, когда сразу пытаешься налепить абстракций и потом втиснуть в них новые правки - получается еще хуже, но это другая история |
|
Обновил(-а) expl 06.10.2010 в 00:41
|
![]() ![]() |
|
@f.g.programmer
появление дополнительных оператор вряд ли может положительно сказаться на производительности. |
![]() ![]() |
|
А я всегда передаю параметр так:
Вешаю на например на кнопки в цикле .name="b"+i; И в функции достаю его e.currentTarget.name.substr(1,e.currentTarget.name.length-1); |
![]() ![]() |
|
Ужас какой. А есть еще DataEvent.
|
![]() ![]() |
|
![]() ![]() |
|
Извините, если не своевременно и не разбираюсь в теме, да и вообще бред напишу, но почему в "4. anonymous func" не использовать код подобного типа:
|
![]() ![]() |
|
А теперь так же, но вне тела listener
![]() |
Последние записи от -De-
- Про память, занимаемую Object и Array и что такое Array (28.08.2011)
- Isometric sorting (23.05.2011)
- разбиралка мат. выражений (28.12.2010)
- как передать параметр в слушатель (14.09.2010)