EventDispatcher对监听器进行管理,围绕着监听器工作。可以添加、删除、暂停/恢复监听器、分发事件到监听器。

1. 一些成员

    /** 把ListenerID和同ID监听器的容器对应 */
std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap; /** 把listenerID的对应的DirtyFlag*/
std::unordered_map<EventListener::ListenerID, DirtyFlag> _priorityDirtyFlagMap; /** 把node和其监听器对应 key:node, value:存储监听器的容器 */
std::unordered_map<Node*, std::vector<EventListener*>*> _nodeListenersMap; /** key: node, value: node优先级 */
std::unordered_map<Node*, int> _nodePriorityMap; /** key: Global Z Order, value: 同gzorder排序好的node*/
std::unordered_map<float, std::vector<Node*>> _globalZOrderNodeMap; /** 存储待添加的监听器 The listeners to be added after dispatching event */
std::vector<EventListener*> _toAddedListeners; /** 存储待删除的监听器 The listeners to be removed after dispatching event */
std::vector<EventListener*> _toRemovedListeners; /** 被脏标记的node */
std::set<Node*> _dirtyNodes;

2. 添加监听器:

2.1 添加和场景图优先级一致的监听器 addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)

参数是监听器、关联的node。监听器优先级自动设为0。

2.2 添加自定优先级的监听器 addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)

参数是监听器、监听器优先级。监听器优先级自定义,不能为0。

两个添加监听器方法都执行了listener->checkAvailable(),在对监听器设置一些成员变量后,调用了addEventListener(listener),下面看addEventListener方法:

2.3.1 addEventListener

该方法用于当分发器正在分发事件时,把监听器用待添加容器存储,而不是直接加到对应的监听器容器里。因为分发事件需要遍历监听器容器,此时不应对容器修改。

当分发器没有分发时,调用forceAddEventListener(listener)方法:

2.3.2 forceAddEventListener

该方法是把监听器直接添加到监听器容器的核心方法。容器是_listenerMap,监听器ID为key,容器Vector为value。同ID的监听器被统一存储。Vector又包含了两个vector容器,根据监听器优先级是否为0存入不同vector里。

监听器优先级为0时,还要用容器建立node和监听器的关联,用容器方便其他方法获取node的所有监听器。建立关联调用associateNodeAndEventListener方法。

2.3.3 associateNodeAndEventListener

用容器_nodeListenersMap存储node关联的所有监听器。

2.4 添加自定义监听器addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)

参数是事件ID、回调函数。优先级自动设为1。

通过ID和回调函数建立自定义监听器对象,调用向容器添加自定优先级监听器方法,把监听器对象加入监听器容器中。

_onCustomEvent是我们指定的回调函数,_onEvent是本方法自动设置的对_onCustomEvent调用的函数,参数为分发到的事件event。

3. 删除监听器

3.1 删除指定的监听器 removeEventListener(EventListener* listener)

如果监听器在待删除容器中,直接从容器中删除。否则,在_listnerMap中遍历查找指定的监听器进行删除,分发器分发事件时,暂缓删除。

dissociateNodeAndEventListener方法,将参数node和参数监听器建立的关联,在容器_nodeListenersMap中删除。

3.2 删除指定类型的监听器 removeEventListenersForType(EventListener::Type listenerType)

该方法对参数listenerType进行判断,再调用removeEventListenersForListenerID,参数为相应监听器类型的LISTENER_ID。

被调用的removeEventListenersForListenerID方法,简要的说,是从_listenerMap查找ID对应的Vector,对Vector的两个存储监听器的容器都清空。清空的操作包括对每个监听器setRegistered(false),删除监听器和node之间的关联,执行release()。之后,删除Vector,还要从_listenerMap中删除。最后,还要从_toAddedListeners容器里删除可能存在的ID监听器。

3.3 删除指定node关联的监听器removeEventListenersForTarget(Node* target, bool recursive/* = false */)

参数为:指定的node,recursive。recursive为true,关联到node子节点的监听器也会被删除,为false则只删除与node关联的。

该方法,简要的说,首先对两个以node为key的容器_nodePriorityMap和_dirtyNodes删除key为node的entry。

再从_nodeListenersMap中找到key为node的监听器容器,对容器中每个监听器执行removeEventListener(EventListener* listener)。

另外,还要在_toAddedListeners中查找有无关联到node的监听器,如有要删除监听器,执行release()。

如果参数recursive为true,对node的所有子节点调用本方法。

3.4 删除指定ID的监听器 removeCustomEventListeners(const std::string& customEventName)

调用了removeEventListenersForListenerID(customEventName)。

3.5 删除所有监听器 removeAllEventListeners()

先获取_listenerMap中所有ID,再调用removeEventListenersForListenerID(type)删除每个ID(type)的监听器。

3.6 删除指定ID的监听器 removeEventListenersForListenerID(listenerID)

先从_listenerMap中获取ID对应的两个监听器容器,再对每个容器的每个监听器setRegistered(false)、删除与node的关联,当没有事件分发时,从容器中删除并执行release(),有事件分发时,在分发事件方法的updateListeners中删除监听器。对_listenerMap中该entry删除。最后还要在_toAddedListeners查找删除对应的监听器。

4. 暂停与恢复监听器

pauseEventListenersForTarget(Node* target, bool recursive/* = false */)

resumeEventListenersForTarget(Node* target, bool recursive/* = false */)

都是对监听器执行setPaused,设置_paused变量。恢复时对node设置脏标记。

5. 进行事件分发 dispatchEvent(Event* event)

这篇文章:事件分发机制

‎Cocos2d-x 学习笔记(15.1) EventDispatcher的更多相关文章

  1. Cocos2d-x 学习笔记(15.2) EventDispatcher 事件分发机制 dispatchEvent(event)

    1. 事件分发方法 EventDispatcher::dispatchEvent(Event* event) 首先通过_isEnabled标志判断事件分发是否启用. 执行 updateDirtyFla ...

  2. ‎Cocos2d-x 学习笔记(15.4) EventDispatcher 事件分发具体逻辑 dispatchEventToListeners函数

    dispatchEvent(Event* event)方法在对事件对应的监听器进行重新排序后,进行事件分发操作.具体操作由dispatchEventToListeners方法执行. 该方法声明: vo ...

  3. ‎Cocos2d-x 学习笔记(15.3) EventDispatcher DirtyFlag 脏标记

    1. 定义 用枚举定义脏标记的4种类型. enum class DirtyFlag { NONE = , FIXED_PRIORITY = << , SCENE_GRAPH_PRIORIT ...

  4. Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法

    Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法 Summary的用法和Group一样简单,分为两步: 启用Summary功能 在Feature标签内,添加如 ...

  5. SQL反模式学习笔记15 分组

    目标:查询得到每组的max(或者min等其他聚合函数)值,并且得到这个行的其他字段 反模式:引用非分组列 单值规则:跟在Select之后的选择列表中的每一列,对于每个分组来说都必须返回且仅返回一直值. ...

  6. 并发编程学习笔记(15)----Executor框架的使用

    Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...

  7. [原创]java WEB学习笔记15:域对象的属性操作(pageContext,request,session,application) 及 请求的重定向和转发

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. Beego 学习笔记15:布局页面

    页面布局 1>     一个html页面由:head部分,body部分,内部css,内部js,外联css,外联的js这几部分组成.因此,一个布局文件也就需要针对这些进行拆分. 2>     ...

  9. Adaptive AUTOSAR 学习笔记 15 - 持久化 Persistency

    本系列学习笔记基于 AUTOSAR Adaptive Platform 官方文档 R20-11 版本 AUTOSAR_EXP_PlatformDesign.pdf.作者:Zijian/TENG 原文地 ...

随机推荐

  1. 〈二〉ElasticSearch的认识:索引、类型、文档

    目录 上节回顾 本节前言 索引index 创建索引 查看索引 查看单个索引 查看所有索引 删除索引 修改索引 修改副本分片数量 关闭索引 索引别名 增加索引别名: 查看索引别名: 删除索引别名: 补充 ...

  2. thinkphp6 常用方法文档

    请求变量 use think\facade\Request; Request::param('name'); Request::param();全部请求变量 返回数组 Request::param([ ...

  3. python+selenium六:隐式等待

    python+selenium六:隐式等待   # 隐式等待 # 全局生效,只写一次即可(仅当前页面)# 若有页面切换,需sleep等待新页面出现后,再使用此方法 # 如:在35秒内,等待操作完成,完 ...

  4. 30 (OC)* 数据结构和算法

    在描述算法时通常用o(1), o(n), o(logn), o(nlogn) 来说明时间复杂度 o(1):是最低的时空复杂度,也就是耗时/耗空间与输入数据大小无关,无论输入数据增大多少倍,耗时/耗空间 ...

  5. Hadoop核心组件之HDFS

    HDFS:分布式文件系统 一句话总结 一个文件先被拆分为多个Block块(会有Block-ID:方便读取数据),以及每个Block是有几个副本的形式存储 1个文件会被拆分成多个Block blocks ...

  6. spring bean的生命周期与springmvc的生命周期

    配置在Spring中的Bean在Spring容器中从加载到销毁会经历那些过程呢?如果实现一些特定的Spring接口,这些特定接口的方法会在什么时候被调用呢?本文简单介绍一下这些过程. Bean在Spr ...

  7. 猿说python

    一.简介         知识改变命运,程序改变世界.互联网时代潜移默化的改变着我们的生活,伴随技术的进步,我想下一个时代应该属于人工智能和机器学习,属于python.           pytho ...

  8. ZK集群的Leader选举源码阅读

    前言 ZooKeeper对Zab协议的实现有自己的主备模型,即Leader和learner(Observer + Follower),有如下几种情况需要进行领导者的选举工作 情形1: 集群在启动的过程 ...

  9. 正睿OI国庆DAY2:图论专题

    正睿OI国庆DAY2:图论专题 dfs/例题 判断无向图之间是否存在至少三条点不相交的简单路径 一个想法是最大流(后来说可以做,但是是多项式时间做法 旁边GavinZheng神仙在谈最小生成树 陈主力 ...

  10. Python 正则re匹配中文、英式数字

    #coding:utf-8 import re s = u''' 或多或少的好好读书电锯惊魂20202 和水电费后是否会时候1212没收到风10.12海大富的是粉红色的和办法的1244525.000 ...