Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Реализация всплытия для не DisplayObject (http://www.flasher.ru/forum/showthread.php?t=152575)

scarbo 20.03.2011 01:30

Реализация всплытия для не DisplayObject
 
Как можно реализовать систему всплытия для не DisplayObject? Конкретно интересует такой момент:
Есть иерархия объектов с 3-4 уровневой вложенностью, необходимо, чтобы родитель мог подписаться на события "внуков" и "правнуков".

КорДум 20.03.2011 01:37

Дедушка слушает сына, сын слушает своего сына?

scarbo 20.03.2011 01:40

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

Bgg 20.03.2011 01:53

Можно создать массив в котором хранятся ссылки на объекты всей ветки, от корня до конца. В переопределенном методе dispatchEvent при bubbles=true обходится массив начиная от event.target и диспатчится тоже событие.

expl 20.03.2011 13:53

Какой массив? Зачем массив?

наследуем детей от этого кода вместо EventDispatcher-а и при добавлении в невизуальный контейнер выставляем у них eventParent на этот контейнер - при удалении зануляем

Код AS3:

package
{
        import flash.events.Event;
        import flash.events.EventDispatcher;
        import flash.events.IEventDispatcher;
 
        public class EventDispatcherWithBubbles extends EventDispatcher
        {
                protected var _eventParent:IEventDispatcher;
 
                public function EventDispatcherWithBubbles()
                {
                      super(this);
                }
 
                public function set eventParent(value:IEventDispatcher):void
                {
                        _eventParent = value;
                }
 
                public function get eventParent():IEventDispatcher
                {
                        return _eventParent;
                }
 
                override public function dispatchEvent(event:Event):Boolean
                {
                        var dispatchResult:Boolean = super.dispatchEvent(event);
                        if (_eventParent != null)
                        {
                                _eventParent.dispatchEvent(event);
                        }
                        return dispatchResult;
                }
        }
}

В контейнере детей можно еще рассылать события ADDED и REMOVED при необходимости

etc 20.03.2011 14:09

expl, в таком варианте событие будет клонироваться при каждом dispatchEvent.

Котяра 20.03.2011 14:12

я делал
Код AS3:

if(parent && event.bubbles)
parent.dispatchEvent(event)

уже опередили, пока писал.
Цитата:

в таком варианте событие будет клонироваться при каждом dispatchEvent.
А в чём проблема?
должен ведь смениться currentTarget

expl 20.03.2011 14:20

Цитата:

expl, в таком варианте событие будет клонироваться при каждом dispatchEvent.
Разве при вызове dispatchEvent оно клонируется. Это какая-то ерунда получается:
Код AS3:

dispatchEvent(new Event(Event.CHANGE));// Один раз создали и еще один раз склонировали?

Да, кстати currentTarget в моём подходе вообще не учитывается - без него как-то обходился

Проверил, НЕ клонируется.

Код AS3:

package 
{
        import flash.display.Sprite;
        import flash.errors.IllegalOperationError;
        import flash.events.Event;
        import flash.events.EventDispatcher;
 
        public class Main extends Sprite
        {
 
                public function Main():void
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
                        // entry point
 
                        var object0:EventDispatcherWithBubbles = new EventDispatcherWithBubbles();
                        var object1:EventDispatcherWithBubbles = new EventDispatcherWithBubbles();
                        object1.eventParent = object0;
 
                        object0.addEventListener(Event.CHANGE, onChange);
                        _event = new Event(Event.CHANGE);
                        object1.dispatchEvent(_event);
                }
 
                private var _event:Event;
 
                private function onChange(event:Event):void
                {
                        if (_event !== event)
                        {
                                throw new Error("_event mast be equals event");// НЕ падает
                        }
                }
        }
 
}


Котяра 20.03.2011 14:25

Если у события не совпадает хозяин и корреспондент - то при рассылке клонируется вроде.

etc 20.03.2011 14:31

Код AS3:

var e:Event = new Event(Event.COMPLETE);
var s:Sprite = new Sprite();
super.addEventListener(Event.COMPLETE, handler);
s.addEventListener(Event.COMPLETE, handler2);
 
function handler(event:Event):void {
        trace(e === event, event.target); // true [object MainTimeline]
        s.dispatchEvent(event);
}
 
function handler2(event:Event):void {
        trace(e === event, event.target); // false, [object Sprite]
}
 
super.dispatchEvent(e);


expl 20.03.2011 14:35

Цитата:

Сообщение от etc (Сообщение 982072)
Код AS3:

var e:Event = new Event(Event.COMPLETE);
var s:Sprite = new Sprite();
super.addEventListener(Event.COMPLETE, handler);
s.addEventListener(Event.COMPLETE, handler2);
 
function handler(event:Event):void {
        trace(e === event, event.target); // true [object MainTimeline]
        s.dispatchEvent(event);
}
 
function handler2(event:Event):void {
        trace(e === event, event.target); // false, [object Sprite]
}
 
super.dispatchEvent(e);


Ну так это же дисплей-объекты, а в моём подходе вручную перенаправляем и дисплей-объектов там нет
Топик всёта-ки "Реализация всплытия для не DisplayObject " называется

А вообще, если currentTarget эмулировать, то клонировать надо-бы и этот currentTarget выставлять

etc 20.03.2011 14:47

Это не принципиально DisplayObject или нет. Если хочется повторить, то надо, чтобы не клонировалось при всплытии :)

expl 20.03.2011 16:17

Ничего не понял.
Попробую задать вопрос по другому: Что надо сделать "Если хочется повторить" и при этом "чтобы не клонировалось при всплытии"?

scarbo 20.03.2011 16:17

Да, currentTarget тоже нужны. Etc, ты раньше писал, что в вашем MVC используется своя система всплытия как раз, не поделишься?

etc 20.03.2011 16:24

scarbo, боюсь, что сейчас это собственность Mail.Ru Group, к которой я отношения никакого не имею.
Кажется, там тоже клонируется событие при всплытии, но точно об этом знает Блуд.

scarbo 20.03.2011 16:27

Ясно, спасибо. Я просто помню ты выкладывал картиночку, где всякие кружочки рисовал взаимосвязи, и там тебя еще спросили, типа как события организованы, на displayobject?ты ответил, что не дай бог. Вот у меня сейчас такая же ситуация.:)

expl 20.03.2011 16:27

Действительно, видимо криво в первый раз проверил, клонируется (не сказал бы что это проблема, но всё же):

Код AS3:

                public function Main():void 
                {
                        var parent:EventDispatcherWithBubbles = new EventDispatcherWithBubbles("parent");
                        var child:EventDispatcherWithBubbles = new EventDispatcherWithBubbles("child");
                        child.eventParent = parent;
 
                        parent.addEventListener(Event.CHANGE, onParentChange);
                        child.addEventListener(Event.CHANGE, onChildChange);
 
                        _event = new Event(Event.CHANGE);
                        child.dispatchEvent(_event);
                }
 
                private var _event:Event;
 
                private function onParentChange(event:Event):void
                {
                        trace("onParentChange:" + event.target);
                        trace("onChildChange: _event == event:" + (_event == event));
                }
 
                private function onChildChange(event:Event):void
                {
                        trace("onChildChange:" + event.target);
                        trace("onChildChange: _event == event:" + (_event == event));
                }

Вывод:
Код:

onChildChange:child
onChildChange: _event == event:true
onParentChange:parent
onChildChange: _event == event:false

Ну не реализовывать же из-за этого механику event-диспетчера вручную.
Более острая проблема - это то что при таком подходе нельзя верить target.
currentTarget вроде правильно всё выдает.

При необходимости придется перегружать target в классе события и присваивать вручную (мне не требовалось просто - обычно таргет в типизированное поле события себя записывает при отправке события)

etc 20.03.2011 16:30

Ну хотя бы target надо сохранить. Уж с клонированием как-нибудь потом. Либо вообще реализовывать свой EventDispatcher, но есть подозрение, что он будет медленным.

Добавлено через 1 минуту
scarbo, да можно и DisplayObject, Димарик например не против совершенно и оно вроде как даже быстрее, правда памяти больше жрёт. Только вот идеологически не очень.

Zebestov 20.03.2011 16:36

Вот здесь Event, в котором при клонировании target тянется от первоисточника.

Psycho Tiger 20.03.2011 18:41

Спросите у dimarik`а. Он мне показывал реализацию своего композитного ED и там, хоть всё достаточно понятно и логично, но очень круто. Кстати, его код распространяется (распространяется ли?) по лицензии MIT.
Мои размышления, когда я сам пытался это сделать (это часть переписки между мной и Димкой, кстати. Надеюсь, он не расстроится что кусок личной переписки выкладываю сюда):
Цитата:

Делаю полную аналогию DisplayObjectContainer (для всплытия баббла), наследуюсь от EventDispatcher. Проще говоря делаю Composite.
Бабблинг не вызывает проблем, обычный редиспатч по родителям.
Бабблю я обёртку над Event, переопределив там методы stopPropogation, stopImmediatlyPropogation, в которых меняю флаги. Если событие было остановлено, то бабблинг останавливается. preventDefault я реализовал так:

Код AS3:

preventedDefault = preventedDefault || !parent.$dispatchEvent(compositeEvent);

После возвращаю !preventDefault от моего переопределенного метода dispatchEvent.
С currentTarget у Event`а в обработчиках думать не надо: он вполне правильно ведёт себя нативно. Из за невозможности создать capture фазу с eventPhase тоже всё просто:

Код AS3:

override public function get eventPhase():uint {
        if (!super.bubbles) return super.eventPhase;
        return eventTarget === currentTarget ? EventPhase.AT_TARGET : EventPhase.BUBBLING_PHASE;
}

eventTarget — это аналог Event#target. Мои наблюдения таковы, что в EventDispatcher#dispatchEvent, если у Event установлен target происходит клонирование события. В своём переопределенном dispatchEvent я клонировал событие сам, назначая ему target. Это порождает проблему: я могу передавать в клон старый target, но событие будет клонироваться дважды, что неприемлемо по производительности. Поэтому я был вынужден создать своё поле eventTarget.
Дмитрий обошёл эту проблему.

scarbo 20.03.2011 19:26

Ок,спрошу.

wvxvw 20.03.2011 20:47

Самое смешное с флешевыми событиями то, что если не мудрствуя лукаво переопределить clone() следующим образом:
Код AS3:

public override function clone():Event { return this; }

То будет облом, потому что диспатчер где-то, блин, запоминает, что уже диспатчил это событие (или даже скорее всего где-то в самом событии это записывает), и со второй попытки продипатчить то же самое событие он просто откажется это делать, молча. Самое смешное, что в виду того, что чуть более чем 99% событий как правило никому не нужны, и просто игнорируются в обработчиках, типичное флеш приложение генерит их тысячи штук в минуту, а то и в секунду... Вот такое вот смелое архитектурное решение...
Что до всплытия - если уж сами организовываете все... я понимаю, стандартный интерфейс, и хочется соответсвовать, но подумайте, а нужны ли вам stopPropagation, stopImmediatePropagation, preventDefault, eventPhase и еще парочка нативных методов, которые сейчас не вспомню, которые будут добавлены в ваши классы событий? Так уж ли часто вы используете что либо из вышеописанного (и знали ли вы вообще, что такие существуют)? :) Я к тому, что если уж делать все с нуля - зачем брать уже готовое, которое работает не так, как вам нужно + половина функионала избыточна? Т.е. конечно, в общем случае изобретать велосипед плохо, но если вам все равно его так или иначе изобретать, то разбирать старый чтобы создать новый?

Psycho Tiger 20.03.2011 20:55

Ага, wvxvw верно написал. Решение проблемы можно взять от dimarik`a: он просто нафигачил декоратор.
Код AS3:

internal var $event:        Event;
public final override function clone():Event {
        return this.$event;
}


dimarik 21.03.2011 22:38

Цитата:

Сообщение от wvxvw (Сообщение 982196)
... будет облом, потому что диспатчер где-то, блин, запоминает, что уже диспатчил это событие (или даже скорее всего где-то в самом событии это записывает), и со второй попытки продипатчить то же самое событие он просто откажется это делать, молча.

Аха, я тоже подивился твоему EventGenerator.

Добавлено через 5 минут
Цитата:

Сообщение от Котяра (Сообщение 982069)
Если у события не совпадает хозяин и корреспондент - то при рассылке клонируется вроде.

Если у события есть target, то оно клонируется в методе dispatchEvent.

scarbo 21.03.2011 23:56

Цитата:

а нужны ли вам stopPropagation, stopImmediatePropagation, preventDefault, eventPhase и еще парочка нативных методов, которые сейчас не вспомню, которые будут добавлены в ваши классы событий? Так уж ли часто вы используете что либо из вышеописанного (и знали ли вы вообще, что такие существуют)?
Да, как ни странно, но знал :). У меня не было задачи сделать полноценную событийную модель, нужно было, чтоб "прадедушка" слушал "внучат" и "правнучат", вот я и подумал, что бабллинг тут уместен.

wvxvw 22.03.2011 00:13

Нет, вы меня не так поняли. Я имел в виду, что эти методы / свойства в подавляющем большинстве случаев не нужны, или, еще хуже - бессмысленны. И именно поэтому знать о них не обязательно. Или, скажем так, не зазорно не знать. Точно так же, как, честно скажу, ни разу не пользовался accessibility, и понятия не имею, как оно работает.

scarbo 22.03.2011 01:08

wvxvw, я понял, ты имеешь ввиду, что их не нужно "имитировать" в своей реализации, они как бы лишние, в довесок. Ок, мне это и не нужно было. Но вот все таки preventDefault и stopImmediatePropagation нужны довольно таки часто.


Часовой пояс GMT +4, время: 10:09.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.