TouchGroupj继承自CCLayer,重写了CCTouchDelegate的四个方法
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
cocostudio编辑器中的控件都是继承自Widget,这些控件都被添加到TouchGroup层中。所有的控件事件的接收都是依靠TouchGroup传递。
bool TouchGroup::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
return checkEventWidget(pTouch, pEvent);
}
bool TouchGroup::checkEventWidget(CCTouch* touch, CCEvent *pEvent)
{
checkTouchEvent(m_pRootWidget,touch, pEvent);
return (m_pSelectedWidgets->count() > 0);
}
bool TouchGroup::checkTouchEvent(Widget *root, CCTouch* touch, CCEvent* pEvent)
{
ccArray* arrayRootChildren = root->getChildren()->data;
int length = arrayRootChildren->num;
for (int i=length-1; i >= 0; i--)
{
Widget* widget = (Widget*)(arrayRootChildren->arr[i]);
if (checkTouchEvent(widget, touch, pEvent))
{
return true;
}
}
bool pass = root->onTouchBegan(touch, pEvent);
if (root->_hitted)
{
m_pSelectedWidgets->addObject(root);
return true;
}
return pass;
}
其中ccTouchBegan方法调用了checkEventWidget,checkEventWidget调用了checkTouchEvent。
checkTouchEvent是一个递归函数。会递归检查TouchGroup中m_pRootWidget的子节点。m_pRootWidget继承自Widget,代表当前父控件,所有子控件加在它之上。
这里有一点值得要提的是往TouchGroup里加控件不要用addChild,要用addWidget,因为触摸事件检查的节点是m_pRootWidget为根的树,所有直接加到TouchGroup中是接收不到触摸事件的。
void TouchGroup::addWidget(Widget* widget)
{
m_pRootWidget->addChild(widget);
}
当控件没有子节点,会调用Widget父函数中的onTouchBegan方法,检查控件的Enable,TouchEnable和hitTest。
所以Cocostudio的控件隐藏用setEnbale(false),不要用setVisible(false).setVisible只是不渲染,但是还是
会接收到事件的,setEnbale的话在渲染和事件的接收都会做判断的。
bool Widget::onTouchBegan(CCTouch *touch, CCEvent *unused_event)
{
_hitted = false;
if (isEnabled() && isTouchEnabled())
{
_touchStartPos = touch->getLocation();
if(hitTest(_touchStartPos) && clippingParentAreaContainPoint(_touchStartPos))
{
_hitted = true;
}
}
if (!_hitted)
{
return false;
}
setFocused(true);
Widget* widgetParent = getWidgetParent();
if (widgetParent)
{
widgetParent->checkChildInfo(0,this,_touchStartPos);
}
pushDownEvent();
return !_touchPassedEnabled;
}
void Widget::setEnabled(bool enabled)
{
_enabled = enabled;
if(_widgetChildren && _widgetChildren->count() > 0)
{
CCObject* child;
CCARRAY_FOREACH(_widgetChildren, child)
{
((Widget*)child)->setEnabled(enabled);
}
}
}
这其中还有一个机制,就是当一个控件接收到事件之后,会先传递给父节点处理.
其中checkChildInfo是个虚函数.控件可以重写这个方法,来接收处理子节点穿过来的事件。
virtual void checkChildInfo(int handleState,Widget* sender,const CCPoint &touchPoint);
其中handleState的值0为begin.1为move,2为end,3为cancel。
这个方法,一般的控件是没有重写的,也就是继续往父节点传,而不做处理。
只有ScrollView,PageView重写这个函数。