Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Автоматическое удаление listener-ов при удалении объекта (http://www.flasher.ru/forum/showthread.php?t=132558)

Bomberovich 14.11.2009 18:16

Автоматическое удаление listener-ов при удалении объекта
 
Доброго времени суток.
Написал простенький класс для вывода мсдж-бокса на экран.


Код AS3:

public class MsgBox extends Sprite {
 
        private const MAX_MSGS_IN_QUEUE:uint = 10;
        public static const TYPE_OK    = 1;
        public static const TYPE_YESNO = 2;
 
        public static const OK        = 1;
        public static const YES        = 2;
        public static const NO        = 3;
 
        private var m_arrMsgs:Vector.<msg_info>;
        private var m_arrBtns:Array;
        private var m_sprBtns:Sprite;
 
 
 
 
        public function MsgBox() {
 
                m_arrMsgs = new Vector.<msg_info>();
                m_sprBtns = new Sprite();
                addChild( m_sprBtns );
                m_sprBtns.addEventListener( MouseEvent.CLICK, OnBtnClick );
                m_arrBtns = new Array();
                visible = false;
 
        } // Конструктор
 
 
 
        public function Create( msg:msg_info ):Boolean {
 
                if( m_arrMsgs.length >= MAX_MSGS_IN_QUEUE )
                        return false;
 
                m_arrMsgs.push( msg );
                if( !visible ) Show();
                return true;
 
        } // Create
 
 
 
        private function Show():void {
 
                TfTitle.text = m_arrMsgs[0].title;
                TfText.text  = m_arrMsgs[0].text;
 
                switch( m_arrMsgs[0].type ) {
 
                        case TYPE_OK: {
                                m_arrBtns[OK]  = CreateButton( "Ok",  xx, yy );
                        } break;
 
                        case TYPE_YESNO: {
                                m_arrBtns[YES] = CreateButton( "Да",  xx, yy );
                                m_arrBtns[ NO] = CreateButton( "Нет", xx, yy );
                        } break;
 
                } // switch
 
 
                if( !visible ) {
                        dispatchEvent( new MsgBoxEvent( MsgBoxEvent.SHOW ) );
                        visible = true;
                }
 
        } // Show
 
 
 
        public function Hide():Boolean {
 
                RemoveAllButtons();
                m_arrMsgs.shift();
 
                if( m_arrMsgs.length == 0 ) {
 
                        dispatchEvent( new MsgBoxEvent( MsgBoxEvent.HIDE ) );
                        visible = false;
                        return true;
 
                } else {
 
                        Show();
                        return false;
                }
 
        } // Hide
 
 
 
        public function OnBtnClick( e:MouseEvent ) {
 
                Hide();
 
        } // OnBtnClick
 
 
 
        private function CreateButton( sCaption:String, x_pos:Number, y_pos:Number ):Button {
 
                var btn:Button = new Button();
                btn.x = x_pos;
                btn.y = y_pos;
                btn.label = sCaption;
                m_sprBtns.addChild( btn );
                return btn;
 
        } // CreateButton
 
 
 
        private function RemoveAllButtons() {
 
                for( var key in m_arrBtns ) {
                        m_sprBtns.removeChild( m_arrBtns[key] );
                        m_arrBtns[key] = null;
                }
                m_arrBtns = null;
                m_arrBtns = new Array();
 
        } // RemoveAllButtons
 
 
 
        public function GetButton ( id:uint )        { return m_arrBtns[id]; }
        public function GetButtons()                { return m_arrBtns;    }

Предполагалось использовать всю эту конструкцию следующим образом:
Код AS3:

m_MsgBox = new MsgBox();
addChild( m_MsgBox );
 
// Создаем мсдж-бокс
var Msg:msg_info = new msg_info();
Msg.type  = MsgBox.TYPE_YESNO;
Msg.title = 'Вы действительно хотите выйти?';
Msg.text  = 'Выход';
m_MsgBox.Create( Msg );
 
// WeakReference слушатели не помешают кнопке удалиться
m_MsgBox.GetButton( MsgBox.YES ).addEventListener( MouseEvent.CLICK, OnExit  , false, 0, true );
m_MsgBox.GetButton( MsgBox.NO  ).addEventListener( MouseEvent.CLICK, Continue, false, 0, true );

Т.е. после того, как создается мсдж-бокс, я просто вешаю на его кнопки слушателей.
И вроде бы всё нормально, но слушателей никто не удаляет. Они так и остаются висеть и ловить сообщения несуществующей кнопки, после того, как мсдж-бокс закрыли. К тому же, приходится использовать WeakReference, чтобы кнопки могли удалиться из памяти.

Прошу совета, как это дело лучше перепроектировать. Переопределить addEventListener для Button? Или вообще запретить получение указателей на кнопки MsgBox-а( тогда при создании мсдж-бокса, нужно будет передать указатель на метод, который дернется при mouseEvent.CLICK )? Или дописывать каждый раз удаление слушателя в вызываемый им же метод? А может есть какой-то секрет удаления слушателей при удалении объекта?

Буду рад услышать любые мнения.

random13 14.11.2009 19:11

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

Psycho Tiger 14.11.2009 19:41

REMOVED_FROM_STAGE, думаю.

Bomberovich 14.11.2009 19:44

Цитата:

Сообщение от random13 (Сообщение 865613)
ну а что вам мешает сделать что то вроде деструктора, который бы вы запускали перед удалением объектов, а в нем удаляли бы ваши слушатели

Деструктор кнопки? А откуда кнопка узнает, какие на ней слушатели висят?

Felicast 14.11.2009 21:31

зачем вам давать доступ кому попало к своим кнопкам. никакого GetButton быть не должно.
надо отсылать события самим классом MsgBox. например, OK_CLICKED, CANCEL_CLICKED.
и подписываться к MsgBox, а не к его кнопкам

Bomberovich 14.11.2009 22:39

Цитата:

Сообщение от Felicast (Сообщение 865645)
зачем вам давать доступ кому попало к своим кнопкам. никакого GetButton быть не должно.
надо отсылать события самим классом MsgBox. например, OK_CLICKED, CANCEL_CLICKED.
и подписываться к MsgBox, а не к его кнопкам

А ничего, что придется переписать все нужные события( PRESS, CLICK, ... ) для всех возможных кнопок? Может быть сделать одно событие MsgBox-а BTN_PRESS, BTN_CLICK,... с полем BtnID, а не для каждой кнопки? Или это те же яйца?

Felicast 15.11.2009 00:19

Цитата:

А ничего, что придется переписать все нужные события( PRESS, CLICK, ... ) для всех возможных кнопок?
да собственно ничего (вы не заглядывали, сколько флексовые компоненты генерируют событий? и это вполне нормально)
Цитата:

Может быть сделать одно событие MsgBox-а BTN_PRESS, BTN_CLICK,... с полем BtnID, а не для каждой кнопки?
можно. только BtnID - строковое обозначение кнопки (типа MsgBox.YES, MsgBox.OK ...)

GentleFLASH 15.11.2009 00:25

Bomberovich, а что мешает MsgBox генерировать событие DESTROY или CLOSE и вам подписываться на это событие, где уже ручками можно было бы снять все листенеры?
Ну или хотя бы коллбак организовать, типа onClose

Bomberovich 15.11.2009 11:59

Felicast
GentleFLASH

Хотелось бы избежать удаления слушателей кнопок(или самого MsgBox-a) внешним классом. Удаляется кнопка - должны удалится все ее слушатели.

Пока в голову приходит только:
Код AS3:

class MsgBox {
 
  // Только с помощью этого метода можно будет повесить любого слушателя на любую кнопку
  public function addEventListenerToButton( uiBtnID:uint, type:String, listener:Function ) {
      m_listeners.push( { uiBtnID:uiBtnID, type:type, listener:listener } );
      m_arrBtns[uiBtnID].addEventListener( type, listener, false, 0, true );
  } // addEventListenerToButton
 
  // Вызывается при удалении кнопок
  private function RemoveAllButtonListeners() {
      for( var i:uint=0; i<m_listeners.length; i++ )
        m_arrBtns[m_listeners[i].uiBtnID].removeEventListener( m_listeners[i].type, m_listeners[i].listener, false, 0, true );
        m_listeners = new Array();
  } // RemoveAllButtonListeners
 
}


etc 15.11.2009 12:29

Можно переопределить addEventListener у самого MsgBox. И вообще, подписываться только у него на кастомные события типа RESULT_YES, RESULT_NO и т. п.. Когда происходит REMOVED_FROM_STAGE, удалять подписчиков.


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

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