win32平台下:cocos2d-x中继承并重写CCTextFieldTTF类,实现密码框输入时,*显示
由于PC端与手机端的键盘输入方式不一样,所以本篇只能在win32平台上进行,或许也可以在MAC,LINUX下进行,但本人未在这两个平台下测试,只在win32下亲测亲证实可以实现密码框的输入*显示,android平台的在下一篇讲述。。。。。。。
一共四个文件,运用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);
}