l

成都手游码农一枚
随笔 - 32, 文章 - 0, 评论 - 117, 引用 - 0
数据加载中……

[cocos2d-x] 分享一个EditBox 控件代码。


实现:直接通过CCIMEDelegate实现字符的录入,删除,支持中英文混合输入,支持多个 EditBox 焦点切换,支持自动调整输入框位置等等一些列,应该满足一般游戏的需求。
主要平台:WIN32,IOS, android未测试。
优点:可以很容易的将 EditBox 控件在 cocos2dx 中融合。
缺点:当然没有原生的功能强。


#ifndef EDITBOX_H_INCLUDED
#define EDITBOX_H_INCLUDED

namespace azl
{

class EditBox;
class EditBoxListener
{
public:
    
virtual void onEditBoxChange(yy::EditBox* editBox) = 0;
    
virtual void onEditBoxReturn(yy::EditBox* editBox) = 0;
}
;

class EditBox : public cocos2d::CCNode, public cocos2d::CCIMEDelegate, public cocos2d::CCTouchDelegate
{
public:
    
enum TYPE
    
{
        TYPE_NORMAL 
= 1,
        TYPE_PASSWORD 
= 2,
    }
;

public:
    EditBox();
    
~EditBox();

public:
    
virtual bool attachWithIME();
    
virtual bool detachWithIME();

public:
    
virtual bool canAttachWithIME() return true; }
    
virtual void didAttachWithIME();
    
virtual bool canDetachWithIME() return true; }
    
virtual void didDetachWithIME();

public:
    
virtual void insertText(const char * text, int len);
    
virtual void deleteBackward();
    
virtual const char * getContentText() 
    
{
        
return getString().c_str();
    }


public:
    
virtual void keyboardWillShow(cocos2d::CCIMEKeyboardNotificationInfo& info);
    
virtual void keyboardDidShow(cocos2d::CCIMEKeyboardNotificationInfo& info);
    
virtual void keyboardWillHide(cocos2d::CCIMEKeyboardNotificationInfo& info);
    
virtual void keyboardDidHide(cocos2d::CCIMEKeyboardNotificationInfo& info);

public:
    
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
virtual void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
virtual void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    
virtual void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);

public:
    
virtual void setContentSize(const cocos2d::CCSize& contentSize)
    
{
        cocos2d::CCNode::setContentSize(contentSize);
        updateString();
    }


public:
    
void updateCursor(float dt);

    
void onEnter();
    
void onExit();
    
void visit();

public:
    
void setBackground(cocos2d::CCNode* background);
    cocos2d::CCNode
* getBackground()
    
{
        
return background_;
    }


    
void setLabel(cocos2d::CCLabelTTF* label);
    cocos2d::CCLabelTTF
* getLabel()
    
{
        
return contentLabel_;
    }


    
void setPlaceholderLabel(cocos2d::CCLabelTTF* label);
    cocos2d::CCLabelTTF
* getPlaceholderLabel()
    
{
        
return placeholderLabel_;
    }


    
void setString(const std::string& text);
    
const std::string& getString()
    
{
        
return contentText_;
    }


    
void setType(TYPE type);
    TYPE getType()
    
{
        
return type_;
    }


    
void setMaxChar(int maxChar);
    
int getMaxChar()
    
{
        
return maxChar_;
    }


    
void setEnabled(bool enable)
    
{
        enable_ 
= enable;
    }

    
bool isEnabled()
    
{
        
return enable_;
    }


    
void setIsNumber(bool number)
    
{
        isNumber_ 
= number;
    }

    
bool isNumber()
    
{
        
return isNumber_;
    }


    
void setListener(EditBoxListener* listener)
    
{
        listener_ 
= listener;
    }

    EditBoxListener
* getListener()
    
{
        
return listener_;
    }


public:
    
static EditBox* create(cocos2d::CCSize size, cocos2d::CCLabelTTF* label, 
        cocos2d::CCLabelTTF
* placeholderLabel = NULL, 
        cocos2d::CCNode
* background = NULL, 
        TYPE type 
= TYPE_NORMAL);

private:
    
void updateString();

private:
    cocos2d::CCNode
* background_;
    cocos2d::CCLabelTTF
* contentLabel_;
    cocos2d::CCLabelTTF
* placeholderLabel_;
    std::
string contentText_;
    TYPE type_;
    
int cursorState_;
    
int maxChar_;
    
bool enable_;
    
float adjustVert_;
    
bool isNumber_;

    EditBoxListener
* listener_;
    std::vector
<unsigned char> lengthStack_;
}
;

}


#endif

// CPP
#include "cocos2d.h"
#include 
"EditBox.h"
#include 
"AppDelegate.h"

using namespace cocos2d;

namespace
{

static const char _charMap[] = 
{
    
/* 00 */    0x000x010x020x030x040x050x060x070x080x090x0a0x0b0x0c0x0d0x0e0x0f
    
/* 10 */    0x100x110x120x130x140x150x160x170x180x190x1a0x1b0x1c0x1d0x1e0x1f
    
/* 20 */    0x200x210x220x230x240x250x260x270x280x290x2a0x2b0x2c0x2d0x2e0x2f
    
/* 30 */    0x300x310x320x330x340x350x360x370x380x390x3a0x3b0x3c0x3d0x3e0x3f
    
/* 40 */    0x400x410x420x430x440x450x460x470x480x490x4a0x4b0x4c0x4d0x4e0x4f
    
/* 50 */    0x500x510x520x530x540x550x560x570x580x590x5a0x5b0x5c0x5d0x5e0x5f
    
/* 60 */    0x600x610x620x630x640x650x660x670x680x690x6a0x6b0x6c0x6d0x6e0x6f
    
/* 70 */    0x700x710x720x730x740x750x760x770x780x790x7a0x7b0x7c0x7d0x7e0x7f
    
/* 80 */      -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    
/* 90 */      -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    
/* a0 */      -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    
/* b0 */      -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    
/* c0 */      -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2
    
/* d0 */      -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2,   -2
    
/* e0 */      -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3
    
/* f0 */      -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -5,   -5,   -5,   -5,   -6,   -6,   -1,   -1
}
;

}


namespace azl
{

static EditBox* g_currentEditBox_ = NULL;

EditBox::EditBox() 
    : background_(NULL)
    , contentLabel_(NULL)
    , placeholderLabel_(NULL)
    , type_(TYPE_NORMAL)
    , cursorState_(
-1)
    , maxChar_(
64)
    , enable_(
true)
    , adjustVert_(
0)
    , isNumber_(
false)
    , listener_(NULL)
{
    
}


EditBox::
~EditBox()
{

}


bool EditBox::attachWithIME()
{
    
bool bRet = CCIMEDelegate::attachWithIME();
    
if (bRet)
    
{
        
// open keyboard
        CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView();
        
if (pGlView)
        
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
            
if (!isNumber())
            
{
                pGlView
->setIMEKeyboardDefault();
                
            }

            
else
            
{
                pGlView
->setIMEKeyboardNumber();
                
            }

#endif
            
            pGlView
->setIMEKeyboardState(true);
        }

    }

    
return bRet;
}


bool EditBox::detachWithIME()
{
    
bool bRet = CCIMEDelegate::detachWithIME();
    
if (bRet)
    
{
        
// close keyboard
        CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView();
        
if (pGlView)
        
{
            pGlView
->setIMEKeyboardState(false);
        }

    }

    
return bRet;
}


void EditBox::didAttachWithIME()
{
    cursorState_ 
= 0;
    g_currentEditBox_ 
= this;
}


void EditBox::didDetachWithIME()
{
    cursorState_ 
= -1;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
    g_currentEditBox_ 
= NULL;
#endif
}


void EditBox::insertText( const char * text, int len )
{
    
if (!enable_ || !isVisible())
    
{
        
return;
    }


    
bool enter = false;
    
bool update = false;

    
for (int i = 0; i < len;)
    
{
        
int l = _charMap[(unsigned char)text[i]];

        
if ((int)contentText_.size() + (l < 0 ? -l : 1> maxChar_)
        
{
            
for (; i < len; ++i)
            
{
                
if (text[i] == '\n')
                
{
                    enter 
= true;
                }

            }


            
break;
        }


        
if (l < 0)
        
{
            
if (!isNumber_)
            
{
                update 
= true;
                lengthStack_.push_back(
-l);
                
for (int j = 0; j < -l; ++j)
                
{
                    contentText_.push_back(text[i 
+ j]);
                }

            }


            i 
+= -l;
        }

        
else
        
{
            
if (text[i] == '\n')
            
{
                enter 
= true;
                
break;
            }


            
if (isNumber_)
            
{
                
if (text[i] >= '0' && text[i] <= '9')
                
{
                    update 
= true;
                    lengthStack_.push_back(
1);
                    contentText_.push_back(text[i]);
                }

            }

            
else
            
{
                update 
= true;
                lengthStack_.push_back(
1);
                contentText_.push_back(text[i]);
            }


            
++i;
        }

    }


    
if (update)
    
{
        updateString();
        
if (listener_)
        
{
            listener_
->onEditBoxChange(this);
        }

    }


    
if (enter)
    
{
        detachWithIME();
        
if (listener_)
        
{
            listener_
->onEditBoxReturn(this);
        }

    }

}


void EditBox::deleteBackward()
{
    
if (!contentText_.empty() && !lengthStack_.empty())
    
{
        contentText_ 
= contentText_.substr(0, contentText_.size() - lengthStack_.back());
        lengthStack_.pop_back();

        updateString();
        
if (listener_)
        
{
            listener_
->onEditBoxChange(this);
        }

    }

}


void EditBox::keyboardWillShow( CCIMEKeyboardNotificationInfo& info )
{
    
if (g_currentEditBox_ != this)
    
{
        
return;
    }

    
    CCNode
* node = this*root = this;
    
while ((node = node->getParent()))
    
{
        root 
= node;
    }

    
    CCPoint position 
= root->getPosition();
    
if (adjustVert_ != 0)
    
{
        root
->setPosition(CCPoint(position.x, position.y - adjustVert_));
    }

    adjustVert_ 
= 0;
    
    CCPoint point 
= convertToWorldSpace(CCPointZero);
    
    
float mY = info.end.getMaxY() + AppDelegate::getKeyboardOffsetY();

    
if (mY > point.y)
    
{
        adjustVert_ 
= mY - point.y + 4 + CCDirector::sharedDirector()->getVisibleOrigin().y;
        position 
= root->getPosition();
        root
->setPosition(CCPoint(position.x, position.y + adjustVert_));
    }

}


void EditBox::keyboardDidShow( CCIMEKeyboardNotificationInfo& info )
{

}


void EditBox::keyboardWillHide( CCIMEKeyboardNotificationInfo& info )
{
    
if (g_currentEditBox_ != this)
    
{
        
return;
    }

    
    
if (adjustVert_ != 0)
    
{
        CCNode
* node = this*root = this;
        
        
while ((node = node->getParent()))
        
{
            root 
= node;
        }

        
        CCPoint position 
= root->getPosition();
        root
->setPosition(CCPoint(position.x, position.y - adjustVert_));
        adjustVert_ 
= 0;
    }


}


void EditBox::keyboardDidHide( CCIMEKeyboardNotificationInfo& info )
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    g_currentEditBox_ 
= NULL;
#endif
}


bool EditBox::ccTouchBegan( CCTouch *pTouch, CCEvent *pEvent )
{
    
if (isVisible() && enable_)
    
{
        CCRect rect;
        rect.origin 
= CCPointZero;
        rect.size 
= getContentSize();
        CCPoint position 
= convertTouchToNodeSpace(pTouch);
        
        
if (rect.containsPoint(position))
        
{
            attachWithIME();
            
return true;
        }

        
else
        
{
            detachWithIME();
        }

    }


    
return false;
}


void EditBox::ccTouchMoved( CCTouch *pTouch, CCEvent *pEvent )
{
    CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);
}


void EditBox::ccTouchEnded( CCTouch *pTouch, CCEvent *pEvent )
{
    CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);
}


void EditBox::ccTouchCancelled( CCTouch *pTouch, CCEvent *pEvent )
{
    CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);
}


void EditBox::updateCursor( float dt )
{
    
if (cursorState_ != -1)
    
{
        cursorState_ 
= (++cursorState_ % 2);
    }

}


void EditBox::onEnter()
{
    schedule(SEL_SCHEDULE(
&EditBox::updateCursor), 0.5);
    CCNode::onEnter();
    CCDirector::sharedDirector()
->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority, true);
}


void EditBox::onExit()
{
    CCDirector::sharedDirector()
->getTouchDispatcher()->removeDelegate(this);
    unschedule(SEL_SCHEDULE(
&EditBox::updateCursor));
    CCNode::onExit();
}


void EditBox::visit()
{
    
if (!isVisible())
    
{
        
return;
    }


    glEnable(GL_SCISSOR_TEST);

    CCPoint position 
= convertToWorldSpace(CCPointZero);
    CCSize size 
= getContentSize();

    CCEGLView::sharedOpenGLView()
->setScissorInPoints(position.x, position.y, size.width, size.height);

    CCNode::visit();

    
if (cursorState_ == 1 && g_currentEditBox_ == this)
    
{
        CCSize size 
= getContentSize();
        CCPoint position1;

        
if (contentLabel_ && contentLabel_->isVisible())
        
{
            CCRect rect 
= contentLabel_->boundingBox();

            
if (size.width <= rect.size.width - 4)
            
{
                position1 
= CCPoint(size.width - 40);
            }

            
else
            
{
                position1 
= CCPoint(rect.size.width, 0);
            }

        }

        
else
        
{
            position1 
= CCPointZero;
        }


        position1.x 
= (position1.x < 2 ? 2 : position1.x);
        position1.y 
= -adjustVert_;

        cocos2d::ccDrawColor4B(
00255128);
        
for (int i = 2; i < 6++i)
        
{
            cocos2d::ccDrawLine(cocos2d::CCPoint(position.x 
+ position1.x + i , position.y + position1.y),
                cocos2d::CCPoint(position.x 
+ position1.x + i , position.y + position1.y + size.height));
        }

    }


    glDisable(GL_SCISSOR_TEST);
}


void EditBox::setBackground( cocos2d::CCNode* background )
{
    
if (background_)
    
{
        removeChild(background_, 
true);
    }

    addChild(background);

    background_ 
= background;
}


void EditBox::setLabel( cocos2d::CCLabelTTF* label )
{
    contentLabel_ 
= label;
    contentLabel_
->setAnchorPoint(CCPointZero);

    updateString();
}


void EditBox::setPlaceholderLabel( cocos2d::CCLabelTTF* label )
{
    placeholderLabel_ 
= label;
    placeholderLabel_
->setAnchorPoint(CCPointZero);

    updateString();
}


void EditBox::setString( const std::string& text )
{
    lengthStack_.clear();
    contentText_ 
= "";
    insertText(text.c_str(), (
int)text.size());
//     contentText_ = text;
// 
//     if (contentLabel_)
//     {
//         contentLabel_->setString(text.c_str());
//     }
// 
//     updateString();
}


void EditBox::setType( TYPE type )
{
    type_ 
= type;

    updateString();
}


void EditBox::setMaxChar( int maxChar )
{
    maxChar_ 
= maxChar;
}


void EditBox::updateString()
{
    
if (contentText_.empty())
    
{
        
if (contentLabel_)
        
{
            contentLabel_
->setString("");
        }


        
if (placeholderLabel_)
        
{
            placeholderLabel_
->setVisible(true);
            
if (contentLabel_)
            
{
                contentLabel_
->setVisible(false);
            }


            CCRect rect 
= placeholderLabel_->boundingBox();
            CCSize size 
= getContentSize();

            placeholderLabel_
->setPosition(CCPoint(0, ( size.height - rect.size.height ) / 2.0f));
        }

    }

    
else
    
{
        
if (contentLabel_)
        
{
            contentLabel_
->setVisible(true);
            
if (placeholderLabel_)
            
{
                placeholderLabel_
->setVisible(false);
            }


            
if (type_ == TYPE_NORMAL)
            
{
                contentLabel_
->setString(contentText_.c_str());
            }

            
else if (type_ == TYPE_PASSWORD)
            
{
                contentLabel_
->setString(std::string().append(lengthStack_.size(), '*').c_str());
            }


            CCRect rect 
= contentLabel_->boundingBox();
            CCSize size 
= getContentSize();

            
float y = ( size.height  - rect.size.height) / 2.0f;

            
if (size.width - 4 <= rect.size.width)
            
{
                contentLabel_
->setPosition(CCPoint(size.width - rect.size.width - 4 , y));
            }

            
else
            
{
                contentLabel_
->setPosition(CCPoint(0, y));
            }

        }

    }

}


EditBox
* EditBox::create( cocos2d::CCSize size, 
    cocos2d::CCLabelTTF
* label, 
    cocos2d::CCLabelTTF
* placeholderLabel /*= NULL*/
    cocos2d::CCNode
* background /*= NULL*/
    TYPE type 
/*=     TYPE_NORMAL*/ )
{
    EditBox
* box = new EditBox;
    box
->autorelease();

    
if (background)
    
{
        background
->setAnchorPoint(CCPointZero);
        background
->setPosition(00);
        box
->addChild(background, 0);
        box
->background_ = background;
    }


    
if (label)
    
{
        label
->setAnchorPoint(CCPointZero);
        box
->addChild(label, 1);
        box
->contentLabel_ = label;
    }


    
if (placeholderLabel)
    
{
        placeholderLabel
->setAnchorPoint(CCPointZero);
        box
->addChild(placeholderLabel, 1);
        box
->placeholderLabel_ = placeholderLabel;
    }


//     {
//         cocos2d::CCMenu* menu = cocos2d::CCMenu::create();
//         cocos2d::CCMenuItemLabel* label = cocos2d::CCMenuItemLabel::create(
//             cocos2d::CCLabelTTF::create("X", "Arial", 20));
//         menu->addChild(label);
//         menu->setPosition(cocos2d::CCPoint(size.width, size.height / 2));
//         box->addChild(menu);
//     }

    box
->setContentSize(size);
    box
->type_ = type;
    box
->updateString();

    
return box;
}


}

 

posted on 2013-07-01 19:51 l1989 阅读(5162) 评论(2)  编辑 收藏 引用 所属分类: C++游戏

评论

# re: [cocos2d-x] 分享一个EditBox 控件代码。  回复  更多评论   

太好了!
2013-09-04 20:15 | 速度

# re: [cocos2d-x] 分享一个EditBox 控件代码。  回复  更多评论   

求教下,你这个类怎么用呢?
2014-03-14 10:37 |

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理