UIButton 事件 响应 分析

  • 本帖最后由 dempsey 于 2013-8-27 00:43 编辑 *

    个人觉得 Cocostudio的UI的系统 还是可以的 毕竟是刚刚起步,还有很多空间需要完善,继续加油!!!且本人c++功底不是一般的差 偶尔看看源码 权当学习了。        其实学习一个新的UI系统,可能我们最容易接触的就是按钮,所以TestCpp的例子就是一个Button的效果展示。
      下面我们跟踪学习下在按下按钮和释放按钮后都发生了什么。
       当进入一个场景后,如果要让场景上Layer响应触摸事件,我们必须给当前Layer  setTouchEnabled为True.这个是一切触摸事件的前提。。
       首先 看例子创建UIButton的代码
    
        UIButton *button = UIButton::create();
        button->setTouchEnable(true);
        button->setTextures("cocosgui/animationbuttonnormal.png", "cocosgui/animationbuttonpressed.png", "");
        button->setPosition(ccp(widgetSize.width / 2.0f, widgetSize.height / 2.0f));
		button->addPushDownEvent(this, coco_pushselector(UIButtonTest::touchBeganEvent));
		button->addMoveEvent(this, coco_moveselector(UIButtonTest::touchMovedEvent));
		button->addReleaseEvent(this, coco_releaseselector(UIButtonTest::touchEndedEvent));
        m_pUiLayer->addWidget(button);

其中: //按下事件
button->addPushDownEvent(this, coco_pushselector(UIButtonTest::touchBeganEvent));
// 移动事件
button->addMoveEvent(this, coco_moveselector(UIButtonTest::touchMovedEvent));
//松开事件
button->addReleaseEvent(this, coco_releaseselector(UIButtonTest::touchEndedEvent));
在所有的控件都是继承于 UIWidget,在UIWidget 里 我们看到

typedef void (CCObject::*SEL_PushEvent)(CCObject*);
typedef void (CCObject::*SEL_MoveEvent)(CCObject*);
typedef void (CCObject::*SEL_ReleaseEvent)(CCObject*);
typedef void (CCObject::*SEL_CancelEvent)(CCObject*);
#define coco_pushselector(_SELECTOR) (cocos2d::extension::SEL_PushEvent)(&_SELECTOR)
#define coco_moveselector(_SELECTOR) (cocos2d::extension::SEL_MoveEvent)(&_SELECTOR)
#define coco_releaseselector(_SELECTOR) (cocos2d::extension::SEL_ReleaseEvent)(&_SELECTOR)
#define coco_cancelselector(_SELECTOR) (cocos2d::extension::SEL_CancelEvent)(&_SELECTOR)
    virtual void addPushDownEvent(CCObject* target,SEL_PushEvent selector);
    virtual void addMoveEvent(CCObject* target,SEL_MoveEvent selector);
    virtual void addReleaseEvent(CCObject* target,SEL_ReleaseEvent selector);
    virtual void addCancelEvent(CCObject* target,SEL_CancelEvent selector);

这里我们举按下这个动作进行分析,其他 移动 和 松手动作 类似。

void UIWidget::addPushDownEvent(CCObject*target, SEL_PushEvent selector)
{
    m_pPushListener = target;
    m_pfnPushSelector = selector;
}

这是向父类UIWidget 注册触摸事件回调 函数。当我们触目屏幕时,UILayer 设置 setTouchEnabled 为True时,cocos2d 为帮我们将事件传递到UILayers上,看UILayer源码:

bool UILayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    if (m_pInputManager && m_pInputManager->onTouchBegan(pTouch))
    {
        return true;
    }
//    CCLOG("ui layer began");
    return false;
}

void UILayer::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
    m_pInputManager->onTouchMoved(pTouch);
//    CCLOG("ui layer move");
}

void UILayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
    m_pInputManager->onTouchEnd(pTouch);
//    CCLOG("ui layer end");
}

这里 m_pInputManager 为studio自己设计管理输入和Wideget管理接口的类 定义如下:

class UIInputManager
{
public:
    UIInputManager();
    ~UIInputManager();
    void registWidget(UIWidget* widget);
    void uiSceneHasChanged();
    void sortWidgets(UIWidget* widget);
    void sortRootWidgets(UIWidget* root);
    void removeManageredWidget(UIWidget* widget);
    UIWidget* checkEventWidget(const CCPoint &touchPoint);
    void addCheckedDoubleClickWidget(UIWidget* widget);
    void update(float dt);
    bool onTouchBegan(CCTouch* touch);
    bool onTouchMoved(CCTouch* touch);
    bool onTouchEnd(CCTouch* touch);
    bool onTouchCancelled(CCTouch* touch);
    
    void setRootWidget(UIWidget* root);
    UIWidget* getRootWidget();

在UILayer 上 通过m_pInputManager 来传递事件,如下:

bool UIInputManager::onTouchBegan(CCTouch* touch)
{
    touchBeganedPoint.x = touch->getLocation().x;
    touchBeganedPoint.y = touch->getLocation().y;
    UIWidget* hitWidget = checkEventWidget(touchBeganedPoint);
    if (!hitWidget)
    {
        m_pCurSelectedWidget = NULL;
        return false;
    }
    m_pCurSelectedWidget = hitWidget;
    hitWidget->onTouchBegan(touchBeganedPoint);
    m_bTouchDown = true;
    return true;
}

其中 checkEventWidget 这个函数是来检测触摸的点是否在UIWidget上,如果没有则返回false,如果 if (m_pInputManager && m_pInputManager->onTouchBegan(pTouch)) 返回false 则继续向下传递触摸事件。
如果hitWidget 不为NULL,则调用响应事件,hitWidget->onTouchBegan(touchBeganedPoint);,返回True 表示消费了此事件。
onTouchBegan 就会到 UIWidget的函数里

void UIWidget::onTouchBegan(const CCPoint &touchPoint)
{
    setFocus(true);
    m_touchStartPos.x = touchPoint.x;
    m_touchStartPos.y = touchPoint.y;
    if (m_pWidgetParent)
    {
        m_pWidgetParent->checkChildInfo(0,this,touchPoint);
    }
    pushDownEvent();
}

其中 setFouch(true);函数

void UIWidget::setFocus(bool fucos)
{
    if (fucos == m_bFocus)
    {
        return;
    }
    m_bFocus = fucos;
    if (m_bFocus)
    {
        setPressState(WidgetStateSelected);
    }
    else
    {
        setPressState(WidgetStateNormal);
    }
}

两个作用:
设置 成员变量为 true;
改变按钮状态
至于 checkChildInfo 函数

void UIWidget::checkChildInfo(int handleState, UIWidget *sender,const CCPoint &touchPoint)
{
    if (m_pWidgetParent)
    {
        m_pWidgetParent->checkChildInfo(handleState,sender,touchPoint);
    }
}

应该是用于容器类型控件的判断 对于UIButton 没有实现这个函数 就可以不考虑了

到 pushDownEvent(); 函数了

void UIWidget::pushDownEvent()
{
    if (m_pPushListener && m_pfnPushSelector)
    {
        (m_pPushListener->*m_pfnPushSelector)(this);
    }
}

就会向我们之前的注册的回调函数进行回调了。
然后就回到 这里啦!!!

void UIButtonTest::touchBeganEvent(CCObject *pSender)
{
    m_pDisplayValueLabel->setText(CCString::createWithFormat("Touch Down")->getCString());
}

Ok Game Over !!!

请问如果想把gui绑定到lua,是怎样使用void UIWidget::addPushDownEvent(CCObject*target, SEL_PushEvent selector)
求大牛解答:12: