Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Двойное событие (http://www.flasher.ru/forum/showthread.php?t=178233)

s3dworld 17.04.2012 23:33

Двойное событие
 
Всем доброго вечера!

У меня есть базовый класс RenderWindow от которого наследуется любое GUI. Собственно поведение RenderWindow устроено так, что он обрабатывает события мыши и посылает события с типом произошедшего события мыши. Собственно вот как это устроено:

Код AS3:

package d.app.render
{
        import d.app.event.AppEvent;
        import d.app.event.appEvent.WindowAppEvent;
        import flash.display.DisplayObject;
        import flash.events.MouseEvent;
 
        public class RenderWindow extends RenderObject
        {
                public static const RW_TYPE_ROOT                                                        :uint                = 0;
                public static const RW_TYPE_MAIN_MENU                                                :uint                = 1;
                public static const RW_TYPE_MAIN_MENU_BUTTON                                :uint                = 2;
                public static const RW_TYPE_CONTEXT_MENU                                        :uint                = 3;
                public static const RW_TYPE_CONTEXT_MENU_ITEM                                :uint                = 4;
                public static const RW_TYPE_TEXT_BUTTON                                                :uint                = 5;
 
                protected var rwType:uint=RW_TYPE_ROOT;
                protected var rwIsListener:Boolean=false;
                protected var rwIsDown:Boolean=false;
 
                public function RenderWindow(_type:uint,_name:String,_parent:RenderObject,_display:DisplayObject)
                {
                        super(RO_TYPE_WINDOW,_name,_parent,_display);
                        rwType=_type;
                        mouseEnabled=true;
                }
 
                public final function rwGetType():uint
                {
                        return rwType;
                }
 
                public function rwBegin():void
                {
                }
 
                public function rwUpdate():void
                {
                }
 
                public function rwResize():void
                {
                }
 
                public function rwEnd():void
                {
                }
 
                public override function roEnable():Boolean
                {
                        if(roIsEnable) return false;
 
                        roIsEnable=true;
 
                        if(!rwIsListener)
                        {
                                addEventListener(MouseEvent.MOUSE_OUT,rwOnMouseOut);
                                addEventListener(MouseEvent.MOUSE_OVER,rwOnMouseOver);
                                addEventListener(MouseEvent.MOUSE_MOVE,rwOnMouseMove);
                                addEventListener(MouseEvent.MOUSE_DOWN,rwOnMouseDown);
                                addEventListener(MouseEvent.MOUSE_UP,rwOnMouseUp);
                        }
 
                        rwOnEnable();
                        return true;
                }
 
                public override function roDisable():Boolean
                {
                        if(!roIsEnable) return false;
 
                        if(rwIsListener)
                        {
                                removeEventListener(MouseEvent.MOUSE_OUT,rwOnMouseOut);
                                removeEventListener(MouseEvent.MOUSE_OVER,rwOnMouseOver);
                                removeEventListener(MouseEvent.MOUSE_MOVE,rwOnMouseMove);
                                removeEventListener(MouseEvent.MOUSE_DOWN,rwOnMouseDown);
                                removeEventListener(MouseEvent.MOUSE_UP,rwOnMouseUp);
                        }
 
                        roIsEnable=false;
                        rwOnDisable();
                        return true;
                }
 
                protected function rwOnEnable():void
                {
                }
 
                protected function rwOnDisable():void
                {
                }
 
                public override function roLock():Boolean
                {
                        if(roIsLock) return false;
                        roIsLock=true;
 
                        if(!rwIsListener)
                        {
                                addEventListener(MouseEvent.MOUSE_OUT,rwOnMouseOut);
                                addEventListener(MouseEvent.MOUSE_OVER,rwOnMouseOver);
                                addEventListener(MouseEvent.MOUSE_MOVE,rwOnMouseMove);
                                addEventListener(MouseEvent.MOUSE_DOWN,rwOnMouseDown);
                                addEventListener(MouseEvent.MOUSE_UP,rwOnMouseUp);
                        }
 
                        rwOnLock();
                        return true;
                }
 
                public override function roUnlock():Boolean
                {
                        if(!roIsLock) return false;
 
                        if(rwIsListener)
                        {
                                removeEventListener(MouseEvent.MOUSE_OUT,rwOnMouseOut);
                                removeEventListener(MouseEvent.MOUSE_OVER,rwOnMouseOver);
                                removeEventListener(MouseEvent.MOUSE_MOVE,rwOnMouseMove);
                                removeEventListener(MouseEvent.MOUSE_DOWN,rwOnMouseDown);
                                removeEventListener(MouseEvent.MOUSE_UP,rwOnMouseUp);
                        }
 
                        roIsLock=false;
                        rwOnUnlock();
                        return true;
                }
 
                protected function rwOnLock():void
                {
                }
 
                protected function rwOnUnlock():void
                {
                }
 
                protected function rwOnMouseOut(_event:MouseEvent):void
                {
                        rwIsDown=false;
                        dispatchEvent(new WindowAppEvent(AppEvent.WINDOW_OUT,this));
                        rwOnAdditionMouseOut(_event);
                }
 
                protected function rwOnMouseOver(_event:MouseEvent):void
                {
                        rwIsDown=false;
                        dispatchEvent(new WindowAppEvent(AppEvent.WINDOW_OVER,this));
                        rwOnAdditionMouseOver(_event);
                }
 
                protected function rwOnMouseMove(_event:MouseEvent):void
                {
                        dispatchEvent(new WindowAppEvent(AppEvent.WINDOW_MOVE,this));
                        rwOnAdditionMouseMove(_event);
                }
 
                protected function rwOnMouseDown(_event:MouseEvent):void
                {
                        rwIsDown=true;
                        dispatchEvent(new WindowAppEvent(AppEvent.WINDOW_DOWN,this));
                        rwOnAdditionMouseDown(_event);
                }
 
                protected function rwOnMouseUp(_event:MouseEvent):void
                {
                        if(rwIsDown) dispatchEvent(new WindowAppEvent(AppEvent.WINDOW_CLICK,this));
                        rwIsDown=false;
                        rwOnAdditionMouseUp(_event);
                }
 
                protected function rwOnAdditionMouseOut(_event:MouseEvent):void
                {
                }
 
                protected function rwOnAdditionMouseOver(_event:MouseEvent):void
                {
                }
 
                protected function rwOnAdditionMouseMove(_event:MouseEvent):void
                {
                }
 
                protected function rwOnAdditionMouseDown(_event:MouseEvent):void
                {
                }
 
                protected function rwOnAdditionMouseUp(_event:MouseEvent):void
                {
                }
 
        }
 
}

Любой наследуемый класс может не переопределять полный список методов, а только добавочные методы. Ну и сам класс наследуется от класса RenderObject (а он предоставляет просто общую информацию и никакого поведения не несёт).

И вот я от RenderWindow наследую два класса:

1. GUIMainMenu
2. GUIMenuButton

GUIMenuButton я прикрепляю к GUIMainMenu в контейнер его. И вот в чём ошибка: когда я тыкаю мышкой на GUIMenuButton, у меня вызывается два события:

1. Событие GUIMenuButton
2. Событие GUIMainMenu

Почему так? Ведь GUIMenuButton лежит в GUIMainMenu и перекрывает его. Тогда почему два события происходят?

Wolsh 17.04.2012 23:59

Обычное всплытие События. Вы считаете, что можете кликнуть по содержимому контейнера, не кликнув при этом по самому контейнеру?

fish_r 18.04.2012 00:01

Потому, видимо, что меню также рассылает событие получателем которого является кнопка, в фазе "захвата". Различить их можно по свойствам currentTarget, и eventPhase.

А в чем удобство вашего такого подхода? Зачем так вообще сделано?

s3dworld 18.04.2012 00:21

Wolsh
Цитата:

Обычное всплытие События. Вы считаете, что можете кликнуть по содержимому контейнера, не кликнув при этом по самому контейнеру?
Честно говоря, я так и считал. Странное если это не так.

fish_r
Цитата:

Потому, видимо, что меню также рассылает событие получателем которого является кнопка, в фазе "захвата". Различить их можно по свойствам currentTarget, и eventPhase.
Дело в том, что каждый RenderObject у меня хранит свойство roName, которое содержит имя объекта. У меню своё имя, у кнопки своё. И когда я получаю событие, я смотрю свойство roName того объекта, который пришёл в событии. Так вот, имена там разные: в первом случае имя кнопки, во втором случае - имя меню.

Цитата:

А в чем удобство вашего такого подхода? Зачем так вообще сделано?
Я уже по такому подхожу почти реализовал одну игру. Это удобно когда я всё наследую от одного класса, а затем объекты различаются на объекты пользовательского интерфейса (RenderWindow) и объекты карты (RenderMap).

Собственно сейчас я пытаюсь сделать главное меню. Нажимаю на кнопку и появляется контекстное меню. А когда я тыкаю в любое другое RenderWindow (то есть имя полученного в событие RenderWindow не совпадёт с именем RenderWindow меню), то я закрываю текущее контекстное меню. То есть есть меню GUIMainMenu, которое полоской простирается во всю ширину экрана. На этой полоске в самом начале (0,0) располагается кнопка меню GUIMenuButton. Как я нажимаю на кнопку, я открываю прикрёплённое за кнопкой GUIContextMenu, а как у меня происходит нажатие на любой другой RenderWindow, то я скрываю контекстное меню (правда оно не скрывается если тыкнули на кнопку, которая наоборот открывает это контекстное меню). Так вот, по сути если открыто контекстное меню и мы тыкнули на главное меню в его любой части, но там где нет кнопки открытия этого контекстного меню, мы должны закрыть меню. Так и происходит. Но когда я тыкаю на кнопку открытия этого меню, у меня приходят два события:

1. Событие GUIMenuButton - контекстное меню открывается
2. Событие GUIMainMenu - контекстное меню закрывается

В результате я никогда не увижу это контекстное меню. Вот зачем оно два события посылает и как это исправить?

fish_r 18.04.2012 00:39

Вот в том то и дело, что Меню рассылает событие получателем которого является Кнопка, в первой фазе event flow. А ваша конструкция не имеет инструментов различения фазы и принадлежности события, поэтому и "захватывает" всё подряд. Почитайте документацию о реализации событий в среде флеш.

По поводу вашего минифреймворка. Может я не правильно, или не до конца понял вашу мысль, но кажется, всё, каким-то... сложным. Я бы например делал бы так:

Код AS3:

   private function onClick( evt:MouseEvent ):void
  {
    // проверяет принадлежность объекта к какому-то классу или его предку
      if( !( evt.target is MenuClass ) ) return;
 
      //further processing
 
  }


s3dworld 18.04.2012 01:13

fish_r
Цитата:

Вот в том то и дело, что Меню рассылает событие получателем которого является Кнопка, в первой фазе event flow.
Так. У меня кнопка лежит в меню. Как меню рассылает кнопке? Это же восходящая цепочка. А мне нужна только нисходящая цепочка - чтобы от детей к родителям. Как этого добиться?

fish_r 18.04.2012 01:25

Вы не правильно понимаете модель распространения событий ( отображаемых объектов), поэтому и говорю, что вам нужно бы ознакомиться с ней, тогда всё станет яснее...

Меню не рассылает кнопке. Меню просто диспатчит событие двигающееся от стейджа к Кнопке. Ваша конструкция обрабатывает это событие так, как будет его получателем является Меню, а на деле это не так. Отсюда и путаница.

В общем случае обрабатывается это так:

Код AS3:

    private function onClick( evt:MouseEvent ):void
    {
        // проверяем - принадлежит ли полученное событие собственно Меню
        if( evt.target !== Menu ) return;
 
      // другой вариант, по фазе события: принадлежит ли событие объекту получателю
        if( evt.eventPhase !== EventPhase.AT_TARGET ) return;
 
    }

Добавлено через 11 минут
То есть я вас сейчас ещё больше запутаю :)

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

s3dworld 18.04.2012 01:37

fish_r
Можете дать ссылку на статью, где понятным языком рассказано про события? Просто то что Вы написали, я не совсем понял.

fish_r 18.04.2012 01:40

Я, вообще, об этом ещё у Мука читал. Там довольно ясно описано. Ну вот есть в документации: http://help.adobe.com/ru_RU/as3/dev/...0204-7dfb.html. Ещё по форуму посмотрите, этот вопрос, конечно не однократно поднимался здесь.

s3dworld 18.04.2012 01:56

fish_r
Спасибо, завтра почитаю. Если будут вопросы, я сюда напишу.


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

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