PDA

Просмотр полной версии : MovieClip не принимает сообщение от родителя


akerka
03.03.2008, 22:14
Есть два класса - app (главный класс флэшки) и receiver (класс находящегося на сцене movie clip, по сути - потомок app);
app посылает сообщение и задача receiver - его услышать. receiver его не слышит. Полагаю, я плохо понимаю механизм посылки сообщений. Если кто либо может взглянуть на пример кода и поправить меня, буду очень благодарен.
В приложенном файле весь пример целиком, а вот сам код

app:
package{
import flash.display.MovieClip;
import flash.events.ProgressEvent;
import flash.events.Event;

public class app extends MovieClip{
public function app(){
loaderInfo.addEventListener(ProgressEvent.PROGRESS,onProgress);
}

public function onProgress(e:ProgressEvent):void {
dispatchEvent(new Event('APP_PROGRESS'));
trace('message sended');
}
}
}

receiver:
package{
import flash.display.MovieClip;
import flash.events.Event;

public class receiver extends MovieClip{
public function receiver(){
addEventListener('APP_PROGRESS', onMessage);
}

public function onMessage(e:Event):void{
trace('message received');
}
}
}

Mr. Fixit
03.03.2008, 22:20
ты же пиши кому извещать..
создай например глобальный инстанс и к нему крепи листенеры..

akerka
03.03.2008, 22:27
Что значит "пиши, кому извещать"? Извещает app. Он - верхний в иерархии класс, глобальнее вроде некуда. А если "кого извещать" - если бы app знал имена потомков то не было бы смысла в сообщениях - проще методы потомков вызывать

akerka
03.03.2008, 22:38
можно написать :
root.addEventListener('APP_PROGRESS', onMessage);
и сообщение принимается, но в документации при работе с сообщениями я таких финтов не вижу. Как я понял, сообщение сходит по дереву иерархии вниз, а если указать
dispatchEvent(new Event('APP_PROGRESS',true));
то и всплывает до самого верха.

Я хочу понять принцип ошибки - где я не понял теорию? - иначе то что я делаю больше похоже на хак.

udaaff
03.03.2008, 23:38
можно написать :
root.addEventListener('APP_PROGRESS', onMessage);
и сообщение принимается, но в документации при работе с сообщениями я таких финтов не вижу. root у вас это app, поэтому обработчик в этом случае благополучно вносится в массив слушателей.
если бы app знал имена потомков то не было бы смысла в сообщениях - проще методы потомков вызывать Проще -- далеко не всегда правильнее.

ps: Названия классов пишутся с большой буквы, а обработчики приватные немешало бы сделать.

etc
04.03.2008, 00:00
А кто вас так научил классы называть и не научил кастомным событиям?

terbooter
04.03.2008, 07:59
Знаю как сделать чтоб работало, но не понимаю почему не работает этот пример. Присоединяюсь к вопросу автора

etc
04.03.2008, 09:18
Нужно использовать всплывающие события. Никаких хаков тут нет, событие от детей поднимается вверх по родителям. Если не использовать bubbling, то событие попадет только в те обработчики, которые были подписаны непосредственно у того, кто шлет событие.

Iv
04.03.2008, 21:03
akerka,
проблемы с твоим кодом возникают из-за идеологически неверно простроеных отношений между классами.
Добиться работоспособности можно, используя bubbling и targeting. Но код в итоге получится корявым.

Что делать:

1. Переименовать. Да-да. Нет слова app в английском. А сократить так можно и appendix и application и, думаю еще не одно слово. Код пишется в первую очередь для человека. Ну, и учесть, что имена классов начинаются с большой буквы.
Это - самое важное. Остальное мелочи.

2. Где-то у тебя создается экземпляр класса receiver (но мы договорились, что переименуем этот класс на более понятное, что-то типа ApplicationPreloaderReceiver). Вот там, где он создается, и нужно передать ссылку на экземпляр класса ныне именуемого app.
И, затем, подпишемся на его события.

зачеркнуто И, затем, подпишем его на события этого класса. /зачеркнуто

3. В коде мы не будем использовать строки и навешивать нехарактерное вещание на класс Event. Просто создадим класс - наследник Event, например ApplicationPreloaderEvent и создадим в нем публичную статическую константу
APPLICATION_PROGRESS:String = "applicationProgress"
и в дальнейшем в коде будем использовать только ее для вещания событий этого типа.

Примерно так.

Теоретически возможно, что передать ссылку на экземпляр app будет затруднительно. В этом случае, коль уж это так тяжело, этот класс следует во-первых переименовать например: MyFirstApplication, а во-вторых сделать его синглтоном и подписываться на событие используя получение ссылки через getInstance(). Впрочем, это не рекомендуемая практика.

удачи.

etc
05.03.2008, 00:26
2. Каким образом? Откроем всем ветрам приватные обработчики событий?
Чем это бабблинг корявый вдруг стал?

Iv
05.03.2008, 01:09
п.2 спасибо, Денис. Там была ошибка по тексту. Исправил.

Баблинг не стал корявым. И тут я ошибся, только в другую сторону: с помощью баблинга вроде как нельзя проинформировать детей.
Так что описаная ситуация невозможна.
Впрочем, я могу ошибаться, не проверял.

Вообще, что касается событий, я бы сказал, что это штука довольно мощная, однако подходить к использованию событий надо с умом и осторожностью.
Теоретически, все вызовы методов можно заменить событиями, однако этого никто не делает, поскольку это усложняет восприятие логики приложения.
Соответственно есть некая грань, которую нужно довольно четко понимать и думать, а стоит ли использовать именно событие.

terbooter
05.03.2008, 08:08
Думаю уместно задать здесь свой вопрос.
Читаю справку и блок Constantiner-a (http://riapriority.com/blogs/constantiner.php/2008/01/22/event_bubbling_again)
пытаюсь разобраться с Event flow. Я представляю себе это так: есть некий объект из дисплэй листа, сам по себе он никагого события из вне отловить не может (естественно), например, нажатие мыши. Флэш плеер говорит этому объекту, знаешь, дорогой генери такое-то событие. (В АС2 было только так). Но в АС3 это событие исходит не сразу от объекта источника, а движется от среды (Flash Player) к этому объекту. Не спроста есть свойство target, название которого как-то замыливается, но если подумать, почему объект стал целью, если он источник. А вот оказывается, он "цель" для события которое имеет точку входа stage.
Это что касается событий которые "из-вне" (клики, загрузка, девайсы...)
Тут мне все понятно, процессом можно управлять: "пузырить", "не пузырить", прекращать распространение и тд.

Не понятно есть ли какой-то поток событий для событий генерируемых "внутри"? Или тут урезанная программа возможна только стадия пузырька?
stage.sprite1.sprite2.sprite3.dispatchEvent(new Event("testEvent", true));

etc
05.03.2008, 09:11
п.2 спасибо, Денис. Там была ошибка по тексту. Исправил.

Баблинг не стал корявым. И тут я ошибся, только в другую сторону: с помощью баблинга вроде как нельзя проинформировать детей.
Так что описаная ситуация невозможна.
Впрочем, я могу ошибаться, не проверял.

Вообще, что касается событий, я бы сказал, что это штука довольно мощная, однако подходить к использованию событий надо с умом и осторожностью.
Теоретически, все вызовы методов можно заменить событиями, однако этого никто не делает, поскольку это усложняет восприятие логики приложения.
Соответственно есть некая грань, которую нужно довольно четко понимать и думать, а стоит ли использовать именно событие.
Бабблинг работает от ребенка к родителю, да.
Что касается вызовов методов, то я по своему опыту могу сказать, что у меня прямые вызовы методов составляют где-то процентов 30 от всех…

terbooter, не очень понял твой вопрос.

terbooter
05.03.2008, 09:19
Если коротко, то:
Существует ли поток событий если объект генерит событие с помощью
dispatchEvent

etc
05.03.2008, 09:22
Если коротко, то:
Существует ли поток событий если объект генерит событие с помощью
dispatchEvent
В смысле бабблинг? Существует, конечно.
Вообще говоря, ничего сложного в работе EventDispatcher нет.

terbooter
05.03.2008, 09:26
Никак не могу сделать примерчик, где событие генерится dispatchEvent,
а у какого-нибудь слушателя оно отрабатывается при этом target != currentTarget или eventPhase != 2;

Пытаюсь делать так:
//пишу код прямо в кадре для быстроты
var s:Sprite=new Sprite();
addChild(s);
s.dispatchEvent(new Event("testEvent",true));

stage.addEventListener("testEvent",testEventHandler);
function testEventHandler(e:Event):void {
trace(e);
}

etc
05.03.2008, 09:32
(кастомный ивент мне было лень писать):
package {
import flash.display.Sprite;
import flash.events.Event;

public class Dispatcher extends Sprite {
public function Dispatcher() {
super();
super.addEventListener(Event.ENTER_FRAME, this.enterFrameHandler);
}

private function enterFrameHandler(event:Event):void {
super.dispatchEvent(new Event('custom', true));
}
}
}

package {
import flash.display.Sprite;
import flash.events.Event;

public class Listener extends Sprite {

public function Listener() {
super();
super.addEventListener('custom', this.customHandler);
super.addChild(new Dispatcher());
}

private function customHandler(event:Event):void {
trace(event);
}
}
}

На выходе получаем:

[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]
[Event type="custom" bubbles=true cancelable=false eventPhase=3]

terbooter
05.03.2008, 09:45
Мой пример тоже заработал !
stage.addEventListener("testEvent",testEventHandler);
function testEventHandler(e:Event):void {
trace(e);
}
var s:Sprite=new Sprite();
addChild(s);
s.dispatchEvent(new Event("testEvent",true));

Это же волшебно! Теперь не буду париться и для каждого блока контроллеров весить листенер. Все листенеры буду весить прямо на сцену.

etc
05.03.2008, 09:55
Все листенеры буду весить прямо на сцену.
Очень опрометчивое решение.

Iv
05.03.2008, 14:00
Прям копи-пастом:
Для передачи событий из View (MVC) удобно использовать bubbling в сочетании со stopPropagation() там, где не требуется дальнейшее всплытие события.
В итоге все события View отлавливаются в Main и далее перенаправляются куда требуется.

toFlash
21.03.2008, 11:52
Прям копи-пастом:
Для передачи событий из View (MVC) удобно использовать bubbling в сочетании со stopPropagation() там, где не требуется дальнейшее всплытие события.
В итоге все события View отлавливаются в Main и далее перенаправляются куда требуется.
Сори, хотел поинтересоваться, вот к примеру у меня есть класс меню, в нем класс итема, я вешаю генерацию события на итем - notify(), как теперь словить это событие на сцене??

Iv
21.03.2008, 13:04
1 событие должно быть с баблингом
2 ты просто в рутовом классе пишешь addEventListener(MyMenuEvent.NOTIFY, onItemNotify);

примерно так