cococococos 2 d-xチャット入力ボックスを実現します.

45026 ワード

回転:http://bbs.9ria.com/thread-216948-1-10.html
チャット入力ボックス  (1行入力ボックス、複数行は自分で拡張できます)
 
実装機能:
1.一般入力
2.入力枠を設定して最大幅(PT値、cococococos 2 d-x座標値)を表示します.
3.入力ボックスで許可される最大文字数(文字Unicode)を設定します.
4.入力ボックスは自動的にインデントされます.文字列の数が表示ボックスの最大幅を超えると自動的に左にインデントされ、最新の文字列が表示されます.
入力ボックス実現コード
 
ヘッダファイル:
 
#ifndef CursorInputDemo_CursorTextField_h
#define CursorInputDemo_CursorTextField_h

#include "cocos2d.h"

USING_NS_CC;

class CursorTextField: public CCTextFieldTTF, public CCTextFieldDelegate, public CCTouchDelegate
{
private:
        //       
        CCPoint m_beginPos;
        //     
        CCSprite *m_pCursorSprite;
        //     
        CCAction *m_pCursorAction;
        //     
        CCPoint m_cursorPos;
        //     
        float inputFrameWidth;
        //          Unicode
        float inputMaxLength;
        int nLenCount;
        int* codeNumType;    //           
        int codeCur;         //       
        int startCur;        //       
        int endCur;          //     
        //       
        std::string *m_pInputText;
        std::string inpuText; //       
public:
        CursorTextField();
        ~CursorTextField();
        // static
        static CursorTextField* textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize);
        // CCLayer
        void onEnter();
        void onExit();
        bool init();
        //        
        void initCursorSprite(int nHeight);

        // 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);

        // CCLayer Touch
        bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
        void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

        //        TextField 
        bool isInTextField(CCTouch *pTouch);
        //   TextField  
        CCRect getRect();

        //      
        void openIME();
        //      
        void closeIME();

        const char* getInputText();
        void setInpuntText(char* text);
        void setInputWidth(float width);
        void setInputMaxLength(float length);

        int Utf82Unicode(LPWSTR out,  int outsize , LPSTR in,int insize);
};

#endif
 
cppファイル:
#include "CursorTextField.h"

const static float DELTA = 0.5f;

using namespace cocos2d;
using namespace std;

CursorTextField::CursorTextField()
{
        CCTextFieldTTF();

        m_pCursorSprite = NULL;
        m_pCursorAction = NULL;

        m_pInputText = NULL;
        codeNumType = NULL;
}

CursorTextField::~CursorTextField()
{
        CC_SAFE_DELETE(m_pInputText);
        CC_SAFE_DELETE_ARRAY(codeNumType);
}

void CursorTextField::onEnter()
{
        CCTextFieldTTF::onEnter();
        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
        this->setDelegate(this);
}

CursorTextField * CursorTextField::textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize)
{
        CursorTextField *pRet = new CursorTextField();
        if(pRet && pRet->initWithString("", fontName, fontSize))
        {
                pRet->autorelease();
                if (placeholder)
                {
                        pRet->setPlaceHolder(placeholder);
                }
                pRet->init();
                pRet->initCursorSprite(fontSize);
                pRet->setHorizontalAlignment(kCCTextAlignmentLeft);
                return pRet;
        }
        CC_SAFE_DELETE(pRet);
        return NULL;
}

bool CursorTextField::init(){
        this->inputFrameWidth = 400;
        this->inputMaxLength = 38;
        this->nLenCount = 0;
        this->codeNumType = new int[50];
        this->codeCur = 0;
        this->startCur = 0;
        this->endCur = 0;
        inpuText = "";
        return true;
}
void CursorTextField::initCursorSprite(const int mHeight)
{
        //      
        const int column = 4;
        const int nHeight = (const int)mHeight;
        int pixels[25][column];
        for (int i=0; i<nHeight; ++i) {
                for (int j=0; j<column; ++j) {
                        pixels[i][j] = 0xffffffff;
                }
        }
        CCTexture2D *texture = new CCTexture2D();
        texture->initWithData(pixels, kCCTexture2DPixelFormat_RGB888, 1, 1, CCSizeMake(column, nHeight));
        m_pCursorSprite = CCSprite::createWithTexture(texture);
        CCSize winSize = getContentSize();
        m_cursorPos = ccp(0, winSize.height / 2);
        m_pCursorSprite->setPosition(m_cursorPos);
        this->addChild(m_pCursorSprite);
        m_pCursorSprite->setVisible(false);
        m_pCursorAction = CCRepeatForever::create((CCActionInterval *) CCSequence::create(CCFadeOut::create(0.25f), CCFadeIn::create(0.25f), NULL));
        m_pCursorSprite->runAction(m_pCursorAction);
        m_pInputText = new std::string();
}

bool CursorTextField::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{    
        m_beginPos = pTouch->getLocation();
        return true;
}

CCRect CursorTextField::getRect()
{
        CCSize size = getContentSize();
        return  CCRectMake(0, -size.height / 2, inputFrameWidth, size.height);
}

//       
const char* CursorTextField::getInputText(){
        const char* text = m_pInputText->c_str();
        return text;
}

//       
void CursorTextField::setInpuntText(char* text){
        *m_pInputText = "";
    setString(text);
        m_pCursorSprite->setPositionX(0);
        CC_SAFE_DELETE_ARRAY(codeNumType);
        codeNumType = new int[50];
        codeCur = 0;
        startCur = 0;
        endCur = 0;
        inpuText = "";
}

//                                
void CursorTextField::setInputWidth(float width){
        this->inputFrameWidth = width;
}

//              Unicode
void CursorTextField::setInputMaxLength(float length){
        this->inputMaxLength = length;
}

//
bool CursorTextField::isInTextField(cocos2d::CCTouch *pTouch)
{
        return getRect().containsPoint(convertTouchToNodeSpaceAR(pTouch));
}

void CursorTextField::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
        CCPoint endPos = pTouch->getLocation();
        //          
        if (::abs(endPos.x - m_beginPos.x) > DELTA || 
                ::abs(endPos.y - m_beginPos.y)) 
        {
                //       
                m_beginPos.x = m_beginPos.y = -1;
                return;
        }

        //                
        isInTextField(pTouch) ? openIME() : closeIME();
}

//           
bool CursorTextField::onTextFieldAttachWithIME(cocos2d::CCTextFieldTTF *pSender)
{
        if (m_pInputText->empty()) {
                return false;
        }
        m_pCursorSprite->setPositionX(getContentSize().width);
        return false;
}

//         
//@param pSender       
//@param text     
//@param        
bool CursorTextField::onTextFieldInsertText(cocos2d::CCTextFieldTTF *pSender, const char *text, int nLen)
{
        std::string sText = m_pInputText->c_str();
        wchar_t* wText = new wchar_t[200];
        char t[200];
        memset(t,0,200);
        strcpy(t,sText.c_str());
        //       Unicode,   Unicode    
        int cou = Utf82Unicode(wText,200,t,sText.length());
        //               
        if(cou >= inputMaxLength) return true;
        //      
        if(text[0] == '
') return true; // m_pInputText->append(text); // CCLabelTTF* ttf = CCLabelTTF::create(text,"Verdana-Bold",26); float teWidth = ttf->getContentSize().width; CCLOG("any code length---%f",teWidth); // inpuText.append(text); // codeNumType[codeCur++] = nLen; std::string* localText = m_pInputText; setString(m_pInputText->c_str()); // if(getContentSize().width > inputFrameWidth){ // , , setString(inpuText.c_str()); while(getContentSize().width > inputFrameWidth){ int nnLen = nLen; if(codeNumType[startCur] == 1){ nnLen = 1; } if(codeNumType[startCur] == 3){ nnLen = 3; } startCur++; nLenCount += nnLen; float gap = localText->size() - nLenCount; inpuText = localText->substr(nLenCount,gap); setString(inpuText.c_str()); float coWidth = getContentSize().width; } } else{ // nLenCount = 0; startCur = 0; setString(m_pInputText->c_str()); } // m_pCursorSprite->setPositionX(getContentSize().width); CC_SAFE_DELETE_ARRAY(wText); return true; } // //@param pSender //@param text //@param bool CursorTextField::onTextFieldDeleteBackward(cocos2d::CCTextFieldTTF *pSender, const char *delText, int nLen) { // nLen m_pInputText->resize(m_pInputText->size() - nLen); // codeNumType[codeCur--] = 0; std::string* localText = m_pInputText; setString(m_pInputText->c_str()); if(getContentSize().width > inputFrameWidth){ // , , while(getContentSize().width > inputFrameWidth){ int nnLen = nLen; if(codeNumType[startCur - 1] == 1){ nnLen = 1; } if(codeNumType[startCur - 1] == 3){ nnLen = 3; } nLenCount -= nnLen; startCur--; if(startCur <=0) startCur = 0; if(nLenCount <=0 ) nLenCount = 0; float gap = localText->size() - nLenCount; const std::string text = localText->substr(nLenCount,gap); setString(text.c_str()); inpuText = text; } } else{ nLenCount = 0; startCur = 0; setString(m_pInputText->c_str()); } // m_pCursorSprite->setPositionX(getContentSize().width); if (m_pInputText->empty()) { m_pCursorSprite->setPositionX(0); } return true; } bool CursorTextField::onTextFieldDetachWithIME(cocos2d::CCTextFieldTTF *pSender) { return false; } void CursorTextField::openIME() { m_pCursorSprite->setVisible(true); this->attachWithIME(); } void CursorTextField::closeIME() { m_pCursorSprite->setVisible(false); this->detachWithIME(); } void CursorTextField::onExit() { CCTextFieldTTF::onExit(); CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); } int CursorTextField::Utf82Unicode(LPWSTR out, int outsize , LPSTR in,int insize) { //------------------------------------------------------------------------------------------- // if(out == NULL || in == NULL || insize<0) { return -1; } int typeCount = 0; int totalNum = 0; char *p = in; for(int i=0;i<insize;i++) { if (*p >= 0x00 && *p <= 0x7f)// '0', utf8 1 ! { p++; totalNum += 1; } else if ((*p & (0xe0))== 0xc0)// , 110, utf8 2 ! { p++; p++; totalNum += 1; } else if ((*p & (0xf0))== 0xe0)// , 1110, utf8 3 ! { p++; p++; p++; totalNum += 1; } } if( outsize < totalNum )// { return -1; } //------------------------------------------------ int resultsize = 0; p = in; char* tmp = (char *)out; while(*p) { if (*p >= 0x00 && *p <= 0x7f)// '0', utf8 1 ! { *tmp = *p; tmp++; //*tmp = '/0'; tmp++; resultsize += 1; } else if ((*p & 0xe0)== 0xc0)// , 110, utf8 2 ! { wchar_t t = 0; char t1 = 0; char t2 = 0; t1 = *p & (0x1f);// 5 !( 110 ) p++; t2 = *p & (0x3f);// 6 !( 10 ) *tmp = t2 | ((t1 & (0x03)) << 6); tmp++; *tmp = t1 >> 2;// tmp++; resultsize += 1; } else if ((*p & (0xf0))== 0xe0)// , 1110, utf8 3 ! { wchar_t t = 0; wchar_t t1 = 0; wchar_t t2 = 0; wchar_t t3 = 0; t1 = *p & (0x1f); p++; t2 = *p & (0x3f); p++; t3 = *p & (0x3f); *tmp = ((t2 & (0x03)) << 6) | t3; tmp++; *tmp = (t1 << 4) | (t2 >> 2); tmp++; resultsize += 1; } p++; } /* , ! *tmp = '/0'; tmp++; *tmp = '/0'; resultsize += 2; */ return resultsize; }
上のコードはUTF-8を通してUnicodeに変換して文字の数を取得します.文字の数が多すぎると、バイトサイズが宣言のchar配列のサイズを超えてしまい、オフラインが発生し、プログラムが崩壊します.
 
解决方法1:限定文字数に応じて、char配列の大きさを最大数として宣言します.
 
解決方法2:プライベート変数を定義するunicodeCount(名前は自由に取る)入力文字の合計数を記録します.オンラインText FieldInsertTextのため、オンラインText FieldDeleteBackwardの2つの方法は、完全な文字を入力したり、完全な文字を減算したりする時に呼び出すので、unicode Count+をオンラインTextFieldInsertTextに入れて、unicodeCountを登録します.UTF-8からUnicodeの操作をやめることができ、オフラインの発生を完全に避け、効率も向上しました.
 
効率面ではまだ最適化されていませんので、自己最適化を参考にして解決策を提供してください.
 
次に、cocococococos 2 d-普通テキスト表示枠に光を書きます.リッチテキストはサポートされていません.主に自動的に改行解決策を提供して、現在のCCLabelTTFの自動改行Bugの代替案を解決します.