cocos2d-x中沿袭并重写CCTextFieldTTF类,实现密码框输入时,显示
cocos2d-x中继承并重写CCTextFieldTTF类,实现密码框输入时,*显示
一共四个文件,运用TestCpp中的inputAction的例子,来完成
继承CCTextFieldTTF,重写virtual void insertText(const char * text, int len);方法,冲定义子类的创建函数,添加保存的代码和输入类型
#ifndef _TESTCPP_TEXTINPUTTEST_H_ #define _TESTCPP_TEXTINPUTTEST_H_ #include "cocos2d.h" #include <iostream> using namespace std; using namespace cocos2d; class CCTextFieldTTF_EXT : public CCTextFieldTTF { public: CCTextFieldTTF_EXT(); ~CCTextFieldTTF_EXT(); virtual void insertText(const char * text, int len); void setm_InputType(int type) { m_InputType = type; } int getType() { return m_InputType; } void setInputSize(int size) { m_TextSize = size; for(int i=0;i!=size;++i) { m_ConstText.push_back('*'); } } public: /** creates a CCTextFieldTTF_EXT from a fontname, alignment, dimension and font size */ static CCTextFieldTTF_EXT * create(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); /** creates a CCLabelTTF from a fontname and font size */ static CCTextFieldTTF_EXT * create(const char *placeholder, const char *fontName, float fontSize); /** initializes the CCTextFieldTTF with a font name, alignment, dimension and font size */ bool initWithPlaceHolder(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); /** initializes the CCTextFieldTTF with a font name and font size */ bool initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize); public: void setStringWithCursor(float t); protected: int m_InputType; int m_TextSize; string m_ConstText; }; #endif
基本上除了插入函数,其他的直接照抄父类,将创建的对象改为子类类型的指针
#include "CCTextFieldTTF_EXT.h" static int _calcCharCount(const char * pszText) { int n = 0; char ch = 0; while ((ch = *pszText)) { CC_BREAK_IF(! ch); if (0x80 != (0xC0 & ch)) { ++n; } ++pszText; } return n; } CCTextFieldTTF_EXT::CCTextFieldTTF_EXT():m_InputType(0),m_TextSize(0) { schedule(schedule_selector(CCTextFieldTTF_EXT::setStringWithCursor), 1.0f); } CCTextFieldTTF_EXT::~CCTextFieldTTF_EXT() {} void CCTextFieldTTF_EXT::insertText(const char * text, int len) { std::string sInsert(text, len); // insert \n means input end int nPos = sInsert.find('\n'); if ((int)sInsert.npos != nPos) { len = nPos; sInsert.erase(nPos); } if (len > 0) { if (m_pDelegate && m_pDelegate->onTextFieldInsertText(this, sInsert.c_str(), len)) { // delegate doesn't want to insert text return; } m_nCharCount += _calcCharCount(sInsert.c_str()); std::string sText(*m_pInputText); sText.append(sInsert); if(!m_InputType) { setString(sText.c_str()); } else { setString(m_ConstText.substr(0,sText.size()).c_str()); } } } CCTextFieldTTF_EXT * CCTextFieldTTF_EXT::create(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize) { CCTextFieldTTF_EXT *pRet = new CCTextFieldTTF_EXT(); if(pRet && pRet->initWithPlaceHolder("", dimensions, alignment, fontName, fontSize)) { pRet->autorelease(); if (placeholder) { pRet->setPlaceHolder(placeholder); } return pRet; } CC_SAFE_DELETE(pRet); return NULL; } CCTextFieldTTF_EXT * CCTextFieldTTF_EXT::create(const char *placeholder, const char *fontName, float fontSize) { CCTextFieldTTF_EXT *pRet = new CCTextFieldTTF_EXT(); if(pRet && pRet->initWithString("", fontName, fontSize)) { pRet->autorelease(); if (placeholder) { pRet->setPlaceHolder(placeholder); } return pRet; } CC_SAFE_DELETE(pRet); return NULL; } ////////////////////////////////////////////////////////////////////////// // initialize ////////////////////////////////////////////////////////////////////////// bool CCTextFieldTTF_EXT::initWithPlaceHolder(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize) { if (placeholder) { CC_SAFE_DELETE(m_pPlaceHolder); m_pPlaceHolder = new std::string(placeholder); } return CCLabelTTF::initWithString(m_pPlaceHolder->c_str(), fontName, fontSize, dimensions, alignment); } bool CCTextFieldTTF_EXT::initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize) { if (placeholder) { CC_SAFE_DELETE(m_pPlaceHolder); m_pPlaceHolder = new std::string(placeholder); } return CCLabelTTF::initWithString(m_pPlaceHolder->c_str(), fontName, fontSize); } void CCTextFieldTTF_EXT::setStringWithCursor(float t) { return; static bool first = true; if(first) { string sCursor = string(getString())+"|"; setString(sCursor.c_str()); first = false; } else { string sCursor = string(getString()); if(sCursor.size()) { sCursor.pop_back();//+"|"; setString(sCursor.c_str()); } first = true; } }
下面修改TestCpp中的例子,主要添加保存的字符对象和删除时星号的显示
#ifndef __TEXT_INPUT_TEST_H__ #define __TEXT_INPUT_TEST_H__ #include "../testBasic.h" class KeyboardNotificationLayer; class CCTextFieldTTF_EXT; /** @brief TextInputTest for retain prev, reset, next, main menu buttons. */ class TextInputTest : public CCLayer { KeyboardNotificationLayer * m_pNotificationLayer; public: TextInputTest(); void restartCallback(CCObject* pSender); void nextCallback(CCObject* pSender); void backCallback(CCObject* pSender); std::string title(); void addKeyboardNotificationLayer(KeyboardNotificationLayer * pLayer); virtual void onEnter(); }; ////////////////////////////////////////////////////////////////////////// // KeyboardNotificationLayer for test IME keyboard notification. ////////////////////////////////////////////////////////////////////////// class KeyboardNotificationLayer : public CCLayer, public CCIMEDelegate { public: KeyboardNotificationLayer(); virtual std::string subtitle() = 0; virtual void onClickTrackNode(bool bClicked) = 0; virtual void registerWithTouchDispatcher(); virtual void keyboardWillShow(CCIMEKeyboardNotificationInfo& info); virtual void insertText(const char * text, int len); // CCLayer virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); protected: CCNode * m_pTrackNode; CCPoint m_beginPos; }; ////////////////////////////////////////////////////////////////////////// // TextFieldTTFDefaultTest for test TextFieldTTF default behavior. ////////////////////////////////////////////////////////////////////////// class TextFieldTTFDefaultTest : public KeyboardNotificationLayer { public: // KeyboardNotificationLayer virtual std::string subtitle(); virtual void onClickTrackNode(bool bClicked); virtual void insertText(const char * text, int len); // CCLayer virtual void onEnter(); }; ////////////////////////////////////////////////////////////////////////// // TextFieldTTFActionTest ////////////////////////////////////////////////////////////////////////// class TextFieldTTFActionTest : public KeyboardNotificationLayer, public CCTextFieldDelegate { CCTextFieldTTF_EXT * m_pTextField; CCAction * m_pTextFieldAction; bool m_bAction; int m_nCharLimit; // the textfield max char limit string str; public: void callbackRemoveNodeWhenDidAction(CCNode * pNode); // KeyboardNotificationLayer virtual std::string subtitle(); virtual void onClickTrackNode(bool bClicked); // CCLayer virtual void onEnter(); virtual void onExit(); // CCTextFieldDelegate virtual bool onTextFieldAttachWithIME(CCTextFieldTTF * pSender); virtual bool onTextFieldDetachWithIME(CCTextFieldTTF * pSender); virtual bool onTextFieldInsertText(CCTextFieldTTF * pSender, const char * text, int nLen); virtual bool onTextFieldDeleteBackward(CCTextFieldTTF * pSender, const char * delText, int nLen); virtual bool onDraw(CCTextFieldTTF * pSender); string initString(int size) { string s= string("************"); return s.substr(0,size); } }; class TextInputTestScene : public TestScene { public: virtual void runThisTest(); }; #endif // __TEXT_INPUT_TEST_H__
创建并测试,将这四个文件copy值TestCpp TextInpuTest文件加下覆盖运行进入TestInput,进入TextFieldTTFActionTest的测试即可看到效果
// #define COCOS2D_DEBUG 1 #include "TextInputTest.h" #include "CCTextFieldTTF_EXT.h" ////////////////////////////////////////////////////////////////////////// // local function ////////////////////////////////////////////////////////////////////////// enum { kTextFieldTTFDefaultTest = 0, kTextFieldTTFActionTest, kTextInputTestsCount, }; #define FONT_NAME "Thonburi" #define FONT_SIZE 36 static int testIdx = -1; KeyboardNotificationLayer* createTextInputTest(int nIndex) { switch(nIndex) { case kTextFieldTTFDefaultTest: return new TextFieldTTFDefaultTest(); case kTextFieldTTFActionTest: return new TextFieldTTFActionTest(); default: return 0; } } CCLayer* restartTextInputTest() { TextInputTest* pContainerLayer = new TextInputTest; pContainerLayer->autorelease(); KeyboardNotificationLayer* pTestLayer = createTextInputTest(testIdx); pTestLayer->autorelease(); pContainerLayer->addKeyboardNotificationLayer(pTestLayer); return pContainerLayer; } CCLayer* nextTextInputTest() { testIdx++; testIdx = testIdx % kTextInputTestsCount; return restartTextInputTest(); } CCLayer* backTextInputTest() { testIdx--; int total = kTextInputTestsCount; if( testIdx < 0 ) testIdx += total; return restartTextInputTest(); } static CCRect getRect(CCNode * pNode) { CCRect rc; rc.origin = pNode->getPosition(); rc.size = pNode->getContentSize(); rc.origin.x -= rc.size.width / 2; rc.origin.y -= rc.size.height / 2; return rc; } ////////////////////////////////////////////////////////////////////////// // implement TextInputTest ////////////////////////////////////////////////////////////////////////// TextInputTest::TextInputTest() : m_pNotificationLayer(0) { } void TextInputTest::restartCallback(CCObject* pSender) { CCScene* s = new TextInputTestScene(); s->addChild(restartTextInputTest()); CCDirector::sharedDirector()->replaceScene(s); s->release(); } void TextInputTest::nextCallback(CCObject* pSender) { CCScene* s = new TextInputTestScene(); s->addChild( nextTextInputTest() ); CCDirector::sharedDirector()->replaceScene(s); s->release(); } void TextInputTest::backCallback(CCObject* pSender) { CCScene* s = new TextInputTestScene(); s->addChild( backTextInputTest() ); CCDirector::sharedDirector()->replaceScene(s); s->release(); } void TextInputTest::addKeyboardNotificationLayer(KeyboardNotificationLayer * pLayer) { m_pNotificationLayer = pLayer; addChild(pLayer); } std::string TextInputTest::title() { return "text input test"; } void TextInputTest::onEnter() { CCLayer::onEnter(); CCSize s = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF* label = CCLabelTTF::create(title().c_str(), "Arial", 24); addChild(label); label->setPosition(ccp(s.width/2, s.height-50)); std::string subTitle = m_pNotificationLayer->subtitle(); if(! subTitle.empty()) { CCLabelTTF* l = CCLabelTTF::create(subTitle.c_str(), "Thonburi", 16); addChild(l, 1); l->setPosition(ccp(s.width/2, s.height-80)); } CCMenuItemImage *item1 = CCMenuItemImage::create("Images/b1.png", "Images/b2.png", this, menu_selector(TextInputTest::backCallback)); CCMenuItemImage *item2 = CCMenuItemImage::create("Images/r1.png","Images/r2.png", this, menu_selector(TextInputTest::restartCallback) ); CCMenuItemImage *item3 = CCMenuItemImage::create("Images/f1.png", "Images/f2.png", this, menu_selector(TextInputTest::nextCallback) ); CCMenu *menu = CCMenu::create(item1, item2, item3, NULL); menu->setPosition(CCPointZero); item1->setPosition(ccp(VisibleRect::center().x - item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2)); item2->setPosition(ccp(VisibleRect::center().x, VisibleRect::bottom().y+item2->getContentSize().height/2)); item3->setPosition(ccp(VisibleRect::center().x + item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2)); addChild(menu, 1); } ////////////////////////////////////////////////////////////////////////// // implement KeyboardNotificationLayer ////////////////////////////////////////////////////////////////////////// KeyboardNotificationLayer::KeyboardNotificationLayer() : m_pTrackNode(0) { setTouchEnabled(true); } void KeyboardNotificationLayer::registerWithTouchDispatcher() { CCDirector* pDirector = CCDirector::sharedDirector(); pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, false); } void KeyboardNotificationLayer::keyboardWillShow(CCIMEKeyboardNotificationInfo& info) { CCLOG("TextInputTest:keyboardWillShowAt(origin:%f,%f, size:%f,%f)", info.end.origin.x, info.end.origin.y, info.end.size.width, info.end.size.height); if (! m_pTrackNode) { return; } CCRect rectTracked = getRect(m_pTrackNode); CCLOG("TextInputTest:trackingNodeAt(origin:%f,%f, size:%f,%f)", rectTracked.origin.x, rectTracked.origin.y, rectTracked.size.width, rectTracked.size.height); // if the keyboard area doesn't intersect with the tracking node area, nothing need to do. if (! rectTracked.intersectsRect(info.end)) { return; } // assume keyboard at the bottom of screen, calculate the vertical adjustment. float adjustVert = info.end.getMaxY() - rectTracked.getMinY(); CCLOG("TextInputTest:needAdjustVerticalPosition(%f)", adjustVert); // move all the children node of KeyboardNotificationLayer CCArray * children = getChildren(); CCNode * node = 0; int count = children->count(); CCPoint pos; for (int i = 0; i < count; ++i) { node = (CCNode*)children->objectAtIndex(i); pos = node->getPosition(); pos.y += adjustVert; node->setPosition(pos); } } void KeyboardNotificationLayer::insertText(const char * text, int len) { if (len >= 12) { return ; } } // CCLayer function bool KeyboardNotificationLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CCLOG("++++++++++++++++++++++++++++++++++++++++++++"); m_beginPos = pTouch->getLocation(); return true; } void KeyboardNotificationLayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { if (! m_pTrackNode) { return; } CCPoint endPos = pTouch->getLocation(); float delta = 5.0f; if (::abs(endPos.x - m_beginPos.x) > delta || ::abs(endPos.y - m_beginPos.y) > delta) { // not click m_beginPos.x = m_beginPos.y = -1; return; } // decide the trackNode is clicked. CCRect rect; CCPoint point = convertTouchToNodeSpaceAR(pTouch); CCLOG("KeyboardNotificationLayer:clickedAt(%f,%f)", point.x, point.y); rect = getRect(m_pTrackNode); CCLOG("KeyboardNotificationLayer:TrackNode at(origin:%f,%f, size:%f,%f)", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); this->onClickTrackNode(rect.containsPoint(point)); CCLOG("----------------------------------"); } ////////////////////////////////////////////////////////////////////////// // implement TextFieldTTFDefaultTest ////////////////////////////////////////////////////////////////////////// std::string TextFieldTTFDefaultTest::subtitle() { return "TextFieldTTF with default behavior test"; } void TextFieldTTFDefaultTest::onClickTrackNode(bool bClicked) { CCTextFieldTTF * pTextField = (CCTextFieldTTF*)m_pTrackNode; if (bClicked) { // TextFieldTTFTest be clicked CCLOG("TextFieldTTFDefaultTest:CCTextFieldTTF attachWithIME"); pTextField->attachWithIME(); } else { // TextFieldTTFTest not be clicked CCLOG("TextFieldTTFDefaultTest:CCTextFieldTTF detachWithIME"); pTextField->detachWithIME(); } } void TextFieldTTFDefaultTest::insertText(const char * text, int len) { int t = strlen(text); int r = len; CCLog(text); } void TextFieldTTFDefaultTest::onEnter() { KeyboardNotificationLayer::onEnter(); // add CCTextFieldTTF CCSize s = CCDirector::sharedDirector()->getWinSize(); CCTextFieldTTF * pTextField = CCTextFieldTTF::textFieldWithPlaceHolder("<click here for input>", FONT_NAME, FONT_SIZE); addChild(pTextField); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) // on android, CCTextFieldTTF cannot auto adjust its position when soft-keyboard pop up // so we had to set a higher position to make it visable pTextField->setPosition(ccp(s.width / 2, s.height/2 + 50)); #else pTextField->setPosition(ccp(s.width / 2, s.height / 2)); #endif m_pTrackNode = pTextField; } ////////////////////////////////////////////////////////////////////////// // implement TextFieldTTFActionTest ////////////////////////////////////////////////////////////////////////// std::string TextFieldTTFActionTest::subtitle() { return "CCTextFieldTTF with action and char limit test"; } void TextFieldTTFActionTest::onClickTrackNode(bool bClicked) { CCTextFieldTTF * pTextField = (CCTextFieldTTF*)m_pTrackNode; if (bClicked) { // TextFieldTTFTest be clicked CCLOG("TextFieldTTFActionTest:CCTextFieldTTF attachWithIME"); pTextField->attachWithIME(); } else { // TextFieldTTFTest not be clicked CCLOG("TextFieldTTFActionTest:CCTextFieldTTF detachWithIME"); pTextField->detachWithIME(); } } void TextFieldTTFActionTest::onEnter() { KeyboardNotificationLayer::onEnter(); m_nCharLimit = 12; // str() m_pTextFieldAction = CCRepeatForever::create( (CCActionInterval*)CCSequence::create( CCFadeOut::create(0.25), CCFadeIn::create(0.25), 0 )); m_pTextFieldAction->retain(); m_bAction = false; // add CCTextFieldTTF CCSize s = CCDirector::sharedDirector()->getWinSize(); m_pTextField = CCTextFieldTTF_EXT::create("<click here for input>", FONT_NAME, FONT_SIZE); m_pTextField->setInputSize(m_nCharLimit); m_pTextField->setm_InputType(1); addChild(m_pTextField); m_pTextField->setDelegate(this); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) // on android, CCTextFieldTTF cannot auto adjust its position when soft-keyboard pop up // so we had to set a higher position m_pTextField->setPosition(ccp(s.width / 2, s.height/2 + 50)); #else m_pTextField->setPosition(ccp(s.width / 2, s.height / 2)); #endif m_pTrackNode = m_pTextField; } void TextFieldTTFActionTest::onExit() { KeyboardNotificationLayer::onExit(); m_pTextFieldAction->release(); } // CCTextFieldDelegate protocol bool TextFieldTTFActionTest::onTextFieldAttachWithIME(CCTextFieldTTF * pSender) { if (! m_bAction) { m_pTextField->runAction(m_pTextFieldAction); m_bAction = true; } return false; } bool TextFieldTTFActionTest::onTextFieldDetachWithIME(CCTextFieldTTF * pSender) { if (m_bAction) { m_pTextField->stopAction(m_pTextFieldAction); m_pTextField->setOpacity(255); m_bAction = false; } return false; } bool TextFieldTTFActionTest::onTextFieldInsertText(CCTextFieldTTF * pSender, const char * text, int nLen) { // if insert enter, treat as default to detach with ime if ('\n' == *text) { return false; } // if the textfield's char count more than m_nCharLimit, doesn't insert text anymore. str.push_back(*text); if (pSender->getCharCount() >= m_nCharLimit) { return true; } // create a insert text sprite and do some action CCLabelTTF * label = CCLabelTTF::create(text, FONT_NAME, FONT_SIZE); this->addChild(label); ccColor3B color = { 226, 121, 7}; label->setColor(color); // move the sprite from top to position CCPoint endPos = pSender->getPosition(); if (pSender->getCharCount()) { endPos.x += pSender->getContentSize().width / 2; } CCSize inputTextSize = label->getContentSize(); CCPoint beginPos(endPos.x, CCDirector::sharedDirector()->getWinSize().height - inputTextSize.height * 2); float duration = 0.5; label->setPosition(beginPos); label->setScale(8); CCAction * seq = CCSequence::create( CCSpawn::create( CCMoveTo::create(duration, endPos), CCScaleTo::create(duration, 1), CCFadeOut::create(duration), 0), CCCallFuncN::create(this, callfuncN_selector(TextFieldTTFActionTest::callbackRemoveNodeWhenDidAction)), 0); label->runAction(seq); return false; } bool TextFieldTTFActionTest::onTextFieldDeleteBackward(CCTextFieldTTF * pSender, const char * delText, int nLen) { // create a delete text sprite and do some action CCLabelTTF * label = CCLabelTTF::create(delText, FONT_NAME, FONT_SIZE); this->addChild(label); str.pop_back(); m_pTextField->setString(initString(str.size()).c_str()); CCLOG(str.c_str()); // move the sprite to fly out CCPoint beginPos = pSender->getPosition(); CCSize textfieldSize = pSender->getContentSize(); CCSize labelSize = label->getContentSize(); beginPos.x += (textfieldSize.width - labelSize.width) / 2.0f; CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCPoint endPos(- winSize.width / 4.0f, winSize.height * (0.5 + (float)rand() / (2.0f * RAND_MAX))); float duration = 1; float rotateDuration = 0.2f; int repeatTime = 5; label->setPosition(beginPos); CCAction * seq = CCSequence::create( CCSpawn::create( CCMoveTo::create(duration, endPos), CCRepeat::create( CCRotateBy::create(rotateDuration, (rand()%2) ? 360 : -360), repeatTime), CCFadeOut::create(duration), 0), CCCallFuncN::create(this, callfuncN_selector(TextFieldTTFActionTest::callbackRemoveNodeWhenDidAction)), 0); label->runAction(seq); return false; } bool TextFieldTTFActionTest::onDraw(CCTextFieldTTF * pSender) { return false; } void TextFieldTTFActionTest::callbackRemoveNodeWhenDidAction(CCNode * pNode) { this->removeChild(pNode, true); } ////////////////////////////////////////////////////////////////////////// // implement TextInputTestScene ////////////////////////////////////////////////////////////////////////// void TextInputTestScene::runThisTest() { CCLayer* pLayer = nextTextInputTest(); addChild(pLayer); CCDirector::sharedDirector()->replaceScene(this); }