一篇好文章关于onEnter与addTargetedDelegate

本文深入解析了Cocos2d-X中触摸事件响应的底层机制,通过分析代码,揭示了无需直接在onEnter中添加触摸事件监听的原因。详细解释了setTouchEnabled函数的作用及CCLayer类中touchDispatcher的工作流程,帮助开发者理解并正确使用触摸事件处理。
       cocos2dx 不要直接在 onEnter 里面 addTargetedDelegate (或 addStandardDelegate)

       今天看别人 cocos2d 代码的时候发现个怪现象, 整个工程里面 没有 setTouchEnabled(true) 这样的代码, 但是程序跑起来的时候却可以响应 触屏事件。于是下断点跟踪啊跟踪,发现 m_bIsTouchEnabled 这个变量确实是 false。。 那么这个layer 到底是怎么响应触摸事件的呢?
存在即合理,空穴不来风。经过别人提醒, 意识到原因在这里:

  virtual void onEnter(){
    CCLayer::onEnter();
    d->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
 }
     类内覆写了 onEnter 函数,并且 addTargetedDelegate , 居然就可以不用 setTouchEnabled 了。 很有意思的样子, 那么不得不看一下 setTouchEnabled 是怎么工作的了。转到 CCLayer.cpp line:151,看到函数实现:


/// isTouchEnabled setter
void CCLayer::setTouchEnabled(bool enabled)
{
    if (m_bIsTouchEnabled != enabled)
    {
        m_bIsTouchEnabled = enabled;
        if (m_bIsRunning)
        {
            if (enabled)
            {
                this->registerWithTouchDispatcher();
            }
            else
            {
                // have problems?
                CCDirector* pDirector = CCDirector::sharedDirector();
                pDirector->getTouchDispatcher()->removeDelegate(this);
            }
        }
    }
}

这个setTouchEnabled 函数做两件事情: 
1. 赋值 m_bIsTouchEnabled = enabled
2. if(m_bIsRunning){ if (enabled) this->registerWithTouchDispatcher(); else removeDelegate(this); }
注意: 这里首先判断 if( m_bIsRunning),就是说,如果在初始化 函数init 里面设定 setTouchEnabled(true), 这时候还没 run起来,所以并不会执行这一段。否则这里 register一次, onEnter 里面默认再 register一次程序就会出问题了

那么 registerWithTouchDispatcher() 干什么事情呢?
跳转到定义可以看到:

void CCLayer::registerWithTouchDispatcher()
{
    CCDirector* pDirector = CCDirector::sharedDirector();
    if (m_pScriptHandlerEntry)
    {
        if (m_pScriptHandlerEntry->isMultiTouches())
        {
            pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);
            LUALOG("[LUA] Add multi-touches event handler: %d", m_pScriptHandlerEntry->getHandler());
        }
        else
        {
            pDirector->getTouchDispatcher()->addTargetedDelegate(this,
                                         m_pScriptHandlerEntry->getPriority(),
                                         m_pScriptHandlerEntry->getSwallowsTouches());
            LUALOG("[LUA] Add touch event handler: %d", m_pScriptHandlerEntry->getHandler());
        }
        return;
    }
    pDirector->getTouchDispatcher()->addStandardDelegate(this,0);
}

除去if (m_pScriptHandlerEntry) 那一段不管(似乎是用来控制 script 代码的行为,我也不大懂), 函数主要做的事情就是一句话:

pDirector->getTouchDispatcher()->addStandardDelegate(this,0);



就是说,默认情况下, CCLayer 注册的是 standardDelegate。

理顺一下, 我们的代码应该:
1. init 函数里面设置 setTouchEnabled(true);
2. 类内覆写函数 registerWithTouchDispatcher, 设置 addStandardDelegate 或者 targetedDelegate,
这样,当初始化时调用 setTouchEnabled(true) 的时候,首先会设置 m_bIsTouchEnabled 为 true, 由于 m_bIsRunning==false, 这时还不会 registerWithTouchDispatcher。 然后程序run起来, 调用 onEnter 函数的时候,这里会(见 CCLayer.cpp line:233):

if (m_bIsTouchEnabled)
    {
        this->registerWithTouchDispatcher();
    }

如果没有 setTouchEnabled, 没有覆写 registerWithTouchDispatcher,而是直接覆写的 onEnter函数,像本文一开始提到的:

virtual void onEnter(){
  CCLayer::onEnter();
  d->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
 }

会怎样?会节省代码吗?不会。因为 m_bIsTouchEnabled==false, 所以 onExit 的时候, CCLayer::onExit() 并不会 removeDelegate, 所以我们还需要手动再覆写 onExit 函数,像这样:


void TestLayer::onExit()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
    CCLayer::onExit();
}


<think>好的,我现在要处理用户的问题,关于SecureHandlerMouseUpDownTemplate、_onenter和_onleave。首先,我需要确认这些术语的具体背景和来源。用户可能是在World of Warcraft的插件开发中遇到这些概念,因为SecureHandler是魔兽世界API中的一部分,用于安全地处理用户界面动作,尤其是在涉及战斗保护机制的情况下。 首先,SecureHandlerMouseUpDownTemplate是一个模板,用于处理鼠标按下和释放事件。魔兽世界的插件系统为了防止作弊,对某些UI操作进行了限制,特别是在战斗中。使用安全模板可以确保插件在这些限制下正常工作。我需要解释这个模板的作用,以及为什么需要使用它,比如避免在战斗中被禁止的操作。 接下来是_onenter和_onleave。这两个可能是处理鼠标进入和离开事件的处理函数。在魔兽世界插件开发中,这些通常框架(如按钮或框架)的事件回调相关。当鼠标悬停在某个UI元素上时触发_onenter,离开时触发_onleave。需要说明它们的用途,比如用于显示提示信息或改变按钮状态,同时也要提到安全机制的限制,确保这些操作不会违反游戏的安全策略。 在整理回答时,需要按照用户的要求,结构清晰,分步骤解释每个术语,同时遵循系统级指令中的格式要求,比如数学表达式用$...$,但在这里可能涉及代码块,需要用正确的格式。不过用户的问题更多是关于编程概念,可能需要用代码示例来说明,但根据系统指令,应避免使用Markdown格式,所以可能需要用文字描述。 需要检查是否有LaTeX语法,但这个问题可能不需要数学公式,更多的是代码和事件处理机制。不过根据系统指令,所有行内数学表达式必须用$...$,但用户的问题中没有数学内容,所以可能不需要。但要注意如果有变量或代码参数,可能需要适当处理。 另外,要确保回答用中文,结构清晰,分点说明每个术语,并提供使用场景和注意事项。同时,要保证信息的准确性,可能需要参考魔兽世界插件开发的官方文档或社区资源,确认SecureHandlerMouseUpDownTemplate的具体用法,以及_onenter和_onleave的正确上下文。 总结步骤: 1. 解释SecureHandlerMouseUpDownTemplate的作用,使用场景,安全机制。 2. 分别说明_onenter和_onleave的事件处理功能,如何模板结合使用。 3. 强调安全模板的重要性,特别是在战斗中的限制。 4. 提供示例或使用方式,但避免Markdown格式,用文字描述。 5. 确保语言简洁,符合中文表达,结构清晰。 可能需要注意的细节: - 安全模板属于安全框架的一部分,确保代码在受限环境中运行。 - _onenter和_onleave是特定于魔兽世界UI框架的回调属性。 - 需要提到这些处理函数如何注册和触发,以及开发者应注意的安全限制。</think>以下是关于**SecureHandlerMouseUpDownTemplate**、**_onenter**和**_onleave**的逐步解释: --- ### 1. SecureHandlerMouseUpDownTemplate - **作用**:这是《魔兽世界》插件开发中用于处理**鼠标按下(MouseDown)和释放(MouseUp)事件**的**安全模板**。 - **背景**:游戏为了保护战斗公平性,禁止插件在战斗中修改某些UI行为(如技能按钮)。此模板通过“安全”机制(SecureHandlers)允许在限制下处理鼠标事件。 - **使用场景**:常用于自定义动作按钮或交互元素,确保其鼠标事件在战斗内外均合法。 - **示例**: 若需创建一个按钮,在鼠标按下时触发技能,需将此模板附加到按钮框架,并通过安全代码(SecureCode)绑定逻辑。 --- ### 2. _onenter _onleave - **定义**:二者是魔兽世界UI框架中用于处理**鼠标悬停进入(OnEnter)和离开(OnLeave)事件**的属性。 - **功能**: - `_onenter`:鼠标进入UI元素(如按钮)时触发,通常用于显示提示信息(Tooltip)或高亮按钮。 - `_onleave`:鼠标离开时触发,用于隐藏提示或恢复按钮状态。 - **安全模板的关系**: - 若需在安全框架内使用这些事件(如战斗中),需通过安全处理器(SecureHandlers)动态注册。 - 非安全代码(如普通插件逻辑)可直接绑定,但需注意战斗保护限制。 --- ### 3. 关键注意事项 - **安全限制**: - 在战斗中,直接修改UI行为(如改变按钮功能)会被阻止。需依赖SecureHandlers预定义的安全操作。 - `SecureHandlerMouseUpDownTemplate`等模板通过沙盒环境确保代码合规。 - **代码示例(文字描述)**: ```lua -- 创建一个安全按钮并绑定模板 local button = CreateFrame("Button", "MySecureButton", UIParent, "SecureHandlerMouseUpDownTemplate") -- 绑定鼠标按下/释放事件的安全代码 button:SetAttribute("_OnMouseDown", [[ -- 安全代码(Lua字符串) ]]) button:SetAttribute("_OnMouseUp", [[ ... ]]) -- 绑定非安全的OnEnter/OnLeave事件(战斗外可用) button:SetScript("OnEnter", function() print("鼠标进入") end) button:SetScript("OnLeave", function() print("鼠标离开") end) ``` --- ### 4. 总结 - **SecureHandlerMouseUpDownTemplate**:安全处理鼠标点击的模板,确保符合游戏战斗规则。 - **_onenter/_onleave**:处理悬停事件的回调属性,需区分安全/非安全场景使用。 - 开发时需遵循暴雪的安全协议,避免插件功能在战斗中被禁用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值