CCB_SELECTORRESOLVER_CCCONTROL_GLUE SEL_MenuHandler SEL_CallFuncN SEL_CCControlHandler
onResolveCCBCCMenuItemSelector
CCB_SELECTORRESOLVER_CALLFUNC_GLUE
要点一:C++解析ccb主要是这几个文件
CCBReader.h/cpp、CCNodeLoaderLibrary.cpp、CCNodeLoader.h/cpp等
CCBReader文件中的CCBReader::readNodeGraph方法是读取ccbi的节点(该方法应该看懂),该方法做的事有
- /* Read class name. */
- std::string className = this->readCachedString();
2.节点名字memberVarAssignmentName
- // Read assignment type and name
- int memberVarAssignmentType = this->readInt(false);
- std::string memberVarAssignmentName;
- if(memberVarAssignmentType != kCCBTargetTypeNone) {
- memberVarAssignmentName = this->readCachedString();
- }
- ...
- CCNodeLoader *ccNodeLoader = this->mCCNodeLoaderLibrary->getCCNodeLoader(className.c_str());
- if (! ccNodeLoader)
- {
- CCLog("no corresponding node loader for %s", className.c_str());
- returnNULL;
- }
- CCNode *node = ccNodeLoader->loadCCNode(pParent, this);
- ...
- // Read properties
- ccNodeLoader->parseProperties(node, pParent, this);
要点二:把CCB原有控件及事件绑定到Lua中(CCControlButton)
在CCNode * CCBReader::readNodeGraph(CCNode * pParent)方法最后加上以下代码
- //-------------------binding lua
- if (memberVarAssignmentName != "") {
- ZGLuaUtils::bindCCBAssign(memberVarAssignmentName.c_str(), className.c_str(), node);
- }
- //-------------------binding lua------end
- void ZGLuaUtils::bindCCBAssign(constchar* assignmentName, constchar *className, CCNode* node) {
- lua_State *L = ((CCLuaEngine*)CCScriptEngineManager::sharedManager()->getScriptEngine())->getLuaStack()->getLuaState();
- lua_getglobal(L, "GF_setCCBBind");
- /**//* Push PARAMETERS to STACK */
- tolua_pushstring(L, assignmentName);
- tolua_pushusertype(L, node, className);
- /**//* Call FUNCTION in LUA */
- int iError;
- iError = lua_pcall(L, //VMachine
- 2, //Argument Count
- LUA_MULTRET, //Return Value Count
- 0);
- if (iError)
- {
- constchar* errorInfo = lua_tostring(L, 1);
- CCLOG("CCBReader::bindCCBAssign pcall FAILED, %s, %d", errorInfo, iError);
- }
- /**//* Check Return Value Types */
- }
上面调用 了Lua中的全局函数也即C++调用Lua拉,查看ZGCCBSupport.lua文件
- GV_CCBVars = nil
- function GF_setCCBBind(nodeKey, node)
- CCBLOG ("binding.."..nodeKey)
- GV_CCBVars[nodeKey] = node
- end
lua中具体实现调用节点控件见LuaLayer.lua文件
- function LuaLayer:createLayer()
- self:initForVars()
- self.layer = CCBReader:nodeGraphFromFile(self.ccbiName)
- self.ccbReader = GV_CCBReader
- self.ccbReader:retain()
- self:initUI()
- local function sceneEventHandler( eventType )
- if eventType == "enter" then
- self:onPreEnter()
- else
- self:onPreExit()
- end
- end
- self.layer:registerScriptHandler(sceneEventHandler)
- return self.layer
- end
- -- init ccb vars
- function LuaLayer:initForVars( )
- self.ccbVars = {}
- self:initVarsForCCB()
- GV_CCBVars = self.ccbVars
- end
1)修改CCNodeLoader.h中的BlockCCControlData加上std::string mSelectorName;
- struct BlockCCControlData {
- SEL_CCControlHandler mSELCCControlHandler;
- CCObject * mTarget;
- std::string mSelectorName;
- int mControlEvents;
- };
- BlockCCControlData * CCNodeLoader::parsePropTypeBlockCCControl(CCNode * pNode, CCNode * pParent, CCBReader * pCCBReader) {
- //-----直接传出带selectorName的BlockData
- std::string selectorName = pCCBReader->readCachedString();
- // 在返回之前,要把下面这个玩意读出来,否则的话会造成读取数据的错位
- pCCBReader->readInt(false); // for int selectorTarget
- pCCBReader->readInt(false); // for int controlEvents
- if(selectorName.length() > 0) {
- BlockCCControlData *blockData = newBlockCCControlData();
- blockData->mSelectorName = selectorName;
- return blockData;
- }
- //-----直接传出带selectorName的BlockData---end
- return NULL;
- }
- #include "CCControlLoader.h"
- #include "ZGLuaUtils.h"
- void CCControlLoader::onHandlePropTypeBlockCCControl(CCNode * pNode, CCNode * pParent, constchar * pPropertyName, BlockCCControlData * pBlockCCControlData, CCBReader * pCCBReader) {
- ZGLuaUtils::bindCCBFunctionForCCControl(pBlockCCControlData->mSelectorName.c_str(), "CCControlButton", pNode, false);
- }
- void ZGLuaUtils::bindCCBFunctionForCCControl(constchar *selectorName, constchar *className, cocos2d::CCNode *node, bool isRegistForTouch) {
- lua_State *L = getLuaState();
- lua_getglobal(L, "GF_setCCBCallback");
- /**//* Push PARAMETERS to STACK */
- tolua_pushusertype(L, node, className);
- tolua_pushstring(L, selectorName);
- tolua_pushboolean(L, isRegistForTouch);
- /**//* Call FUNCTION in LUA */
- int iError;
- iError = lua_pcall(L, //VMachine
- 3, //Argument Count
- LUA_MULTRET, //Return Value Count
- 0);
- if (iError)
- {
- constchar* errorInfo = lua_tostring(L, 1);
- CCLOG("CCBReader::bindCCBFunctionForCCControl pcall FAILED, %s, %d", errorInfo, iError);
- }
- /**//* Check Return Value Types */
- }
- function GF_setCCBCallback(node, callbackKey, isRegistForTouch)
- CCBLOG ("binding callback.."..callbackKey)
- local value = GV_CCBVars[callbackKey]
- if isRegistForTouch then
- -- registe for CCControlButton and others
- node:registerScriptTouchHandler(GV_CCBVars[callbackKey])
- else
- -- registe for CCMenuItems
- GF_dump(node, "node")
- GF_dump(callbackKey, "callbackKey")
- node:registerScriptTapHandler(GV_CCBVars[callbackKey])
- end
- end
4)修改CCControlButton.h文件增加以下代码
- // add lua touch support
- protected:
- int m_nScriptTapHandler;
- public:
- virtualvoid registerScriptTapHandler(int nHandler);
- virtualvoid unregisterScriptTapHandler(void);
- int getScriptTapHandler() { returnm_nScriptTapHandler; };
- / add lua touch support
- #include "script_support/CCScriptSupport.h"
- #include "ZGLuaUtils.h"
- voidCCControlButton::registerScriptTapHandler(int nHandler)
- {
- unregisterScriptTapHandler();
- m_nScriptTapHandler = nHandler;
- LUALOG("[LUA] Add CCMenuItem script handler: %d", m_nScriptTapHandler);
- }
- voidCCControlButton::unregisterScriptTapHandler(void)
- {
- if (m_nScriptTapHandler)
- {
- CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptHandler(m_nScriptTapHandler);
- LUALOG("[LUA] Remove CCMenuItem script handler: %d", m_nScriptTapHandler);
- m_nScriptTapHandler = 0;
- }
- }
说明:如果Lua在C++中注册回调函数。也即向C++的函数传的参是Lua函数,但C++函数形参却是int型(Lua函数的标号即句柄),在这里程序启动后,每注册一个回调则回调的函数标识是加1的,即句柄是自增长的int型
上面已经实现在Lua中绑定事件即Lua中注册事件但还要在Lua中实现响应事件
6)修改CCControlButton.cpp文件
- /**(i)在 CCControlButton::~CCControlButton()方法体内加上unregisterScriptTapHandler();
- **(ii)在 ccTouchEnded方法实现调用注册的事件即加上以下代码
- **if (m_nScriptTapHandler != 0) {
- ** ZGLuaUtils::getLuaEngine()->executeControlButtonEvent(this);
- **}
- **/
- void CCControlButton::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
- {
- m_isPushed = false;
- setHighlighted(false);
- if (isTouchInside(pTouch))
- {
- sendActionsForControlEvents(CCControlEventTouchUpInside);
- if (m_nScriptTapHandler != 0) {
- ZGLuaUtils::getLuaEngine()->executeControlButtonEvent(this);
- }
- }
- else
- {
- sendActionsForControlEvents(CCControlEventTouchUpOutside);
- }
- }
- //修改.h文件增加以下代码
- #include "cocos-ext.h"
- virtual int executeControlButtonEvent(cocos2d::extension::CCControlButton *controlButton);
- //修改.cpp文件增加以下代码
- int CCLuaEngine::executeControlButtonEvent(cocos2d::extension::CCControlButton *controlButton) {
- int nHandler = controlButton->getScriptTapHandler();
- if (!nHandler) return0;
- m_stack->pushInt(controlButton->getTag());
- m_stack->pushCCObject(controlButton, "CCControlButton");
- returnm_stack->executeFunctionByHandler(nHandler, 2);
- }
1)CCLuaEngin.h/ccp 其它一些控件类会调用CCLuaEngin中的一些方法,而本类又是C++调用Lua堆栈,用处是处理控件和控件的事件响应
- //修改.h文件,加上以下代码
- #include "CCScrollLayerButton.h"
- virtual int executeScrollLayerButtonEvent(CCScrollLayerButton *scrollLayerButton);
- //修改.cpp文件,加上以下代码
- int CCLuaEngine::executeScrollLayerButtonEvent(CCScrollLayerButton *scrollLayerButton) {
- int nHandle = scrollLayerButton->getScriptTapHandler();
- if (!nHandle) return 0;
- m_stack->pushInt(scrollLayerButton->getTag());
- m_stack->pushCCObject(scrollLayerButton, "CCScrollLayerButton");
- return m_stack->executeFunctionByHandler(nHandle, 2);
- }
3)修改CCBReader.cpp CCNode * CCBReader::readNodeGraph(CCNode * pParent)方法最后加上以下代码
- //-------------------binding lua
- if (memberVarAssignmentName != "") {
- //CCScrollLayerButton特殊处理
- if (strcmp(className.c_str(), "CCScrollLayerButton") == 0) {
- vector<string> stringVec;
- ZGStringUtils::splitString(memberVarAssignmentName, "@", stringVec);
- string member = stringVec[0];
- string function = stringVec[1];
- //bind var name
- ZGLuaUtils::bindCCBAssign(member.c_str(), "CCScrollLayerButton", node);
- //bind function
- ZGLuaUtils::bindCCBFunctionForCCControl(function.c_str(), "CCScrollLayerButton", node, false);
- }else{
- ZGLuaUtils::bindCCBAssign(memberVarAssignmentName.c_str(), className.c_str(), node);
- }
- }
- //-------------------binding lua------end
bindCCBFunctionForCCControl方法调用lua中的方法ZGCCBSupport.lua 文件中的GF_setCCBCallback方法,而方法又调用了节点的node:registerScriptTapHandler(GV_CCBVars[callbackKey]), 因为Lua调用c++代码且是自定义控件所以ZGToLua中加入CCScrollLayerButton的registerScriptTapHandler方法
4)但是由上面要点一第3小点可得CCBReader还会解析控件的属性所以必须加上以下代码,当然也要在项目上加上CCScrollLayerButtonLoader.h文件
- #include "CCScrollLayerButtonLoader.h"
- voidCCNodeLoaderLibrary::registerDefaultCCNodeLoaders() {
- this->registerCCNodeLoader("CCScrollLayerButton", CCScrollLayerButtonLoader::loader());
- }