转自:http://bbs.9ria.com/thread-216948-1-10.html

聊天输入框  (单行输入框 ,多行可自己扩展)

实现功能:

1.普通输入

2.设置输入框显示最大宽度(PT值,cocos2d-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,,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 = ;
this->inputMaxLength = ;
this->nLenCount = ;
this->codeNumType = new int[];
this->codeCur = ;
this->startCur = ;
this->endCur = ;
inpuText = "";
return true;
}
void CursorTextField::initCursorSprite(const int mHeight)
{
// 初始化光标
const int column = ;
const int nHeight = (const int)mHeight;
int pixels[][column];
for (int i=; i<nHeight; ++i) {
for (int j=; j<column; ++j) {
pixels[i][j] = 0xffffffff;
}
}
CCTexture2D *texture = new CCTexture2D();
texture->initWithData(pixels, kCCTexture2DPixelFormat_RGB888, , , CCSizeMake(column, nHeight));
m_pCursorSprite = CCSprite::createWithTexture(texture);
CCSize winSize = getContentSize();
m_cursorPos = ccp(, winSize.height / );
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(, -size.height / , 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();
CC_SAFE_DELETE_ARRAY(codeNumType);
codeNumType = new int[];
codeCur = ;
startCur = ;
endCur = ;
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 = -;
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[];
char t[];
memset(t,,);
strcpy(t,sText.c_str());
//将字符串转换为Unicode,并返回Unicode字符数量
int cou = Utf82Unicode(wText,,t,sText.length());
//当字符数量超过规定值 不做处理
if(cou >= inputMaxLength) return true;
//屏蔽回车输入
if(text[] == '\n')
return true;
//输入框总内容添加
m_pInputText->append(text); //测试
CCLabelTTF* ttf = CCLabelTTF::create(text,"Verdana-Bold",);
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] == ){
nnLen = ;
}
if(codeNumType[startCur] == ){
nnLen = ;
}
startCur++;
nLenCount += nnLen;
float gap = localText->size() - nLenCount;
inpuText = localText->substr(nLenCount,gap);
setString(inpuText.c_str());
float coWidth = getContentSize().width;
}
}
else{
//小于,直接设置显示总字符串
nLenCount = ;
startCur = ;
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--] = ;
std::string* localText = m_pInputText;
setString(m_pInputText->c_str());
if(getContentSize().width > inputFrameWidth){
//大于指定宽度,截取字符串,直到字符串长度小于指定宽度
while(getContentSize().width > inputFrameWidth){
int nnLen = nLen;
if(codeNumType[startCur - ] == ){
nnLen = ;
}
if(codeNumType[startCur - ] == ){
nnLen = ;
}
nLenCount -= nnLen;
startCur--;
if(startCur <=)
startCur = ;
if(nLenCount <= )
nLenCount = ;
float gap = localText->size() - nLenCount;
const std::string text = localText->substr(nLenCount,gap);
setString(text.c_str());
inpuText = text;
}
}
else{
nLenCount = ;
startCur = ;
setString(m_pInputText->c_str());
}
//设置光标位置
m_pCursorSprite->setPositionX(getContentSize().width);
if (m_pInputText->empty()) {
m_pCursorSprite->setPositionX();
} 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<)
{
return -;
}
int typeCount = ;
int totalNum = ;
char *p = in;
for(int i=;i<insize;i++)
{
if (*p >= 0x00 && *p <= 0x7f)//说明最高位为'0',这意味着utf8编码只有1个字节!
{
p++;
totalNum += ;
}
else if ((*p & (0xe0))== 0xc0)//只保留最高三位,看最高三位是不是110,如果是则意味着utf8编码有2个字节!
{
p++;
p++;
totalNum += ;
}
else if ((*p & (0xf0))== 0xe0)//只保留最高四位,看最高三位是不是1110,如果是则意味着utf8编码有3个字节!
{
p++;
p++;
p++;
totalNum += ;
}
}
if( outsize < totalNum )//参数有效性判断!
{
return -;
}
//------------------------------------------------
int resultsize = ; p = in;
char* tmp = (char *)out;
while(*p)
{
if (*p >= 0x00 && *p <= 0x7f)//说明最高位为'0',这意味着utf8编码只有1个字节!
{
*tmp = *p;
tmp++;
//*tmp = '/0';
tmp++;
resultsize += ;
}
else if ((*p & 0xe0)== 0xc0)//只保留最高三位,看最高三位是不是110,如果是则意味着utf8编码有2个字节!
{
wchar_t t = ;
char t1 = ;
char t2 = ; t1 = *p & (0x1f);//高位的后5位!(去除了头部的110这个标志位)
p++;
t2 = *p & (0x3f);//低位的后6位!(去除了头部的10这个标志位) *tmp = t2 | ((t1 & (0x03)) << );
tmp++;
*tmp = t1 >> ;//留下其保留的三位
tmp++;
resultsize += ;
}
else if ((*p & (0xf0))== 0xe0)//只保留最高四位,看最高三位是不是1110,如果是则意味着utf8编码有3个字节!
{
wchar_t t = ;
wchar_t t1 = ;
wchar_t t2 = ;
wchar_t t3 = ;
t1 = *p & (0x1f);
p++;
t2 = *p & (0x3f);
p++;
t3 = *p & (0x3f); *tmp = ((t2 & (0x03)) << ) | t3;
tmp++;
*tmp = (t1 << ) | (t2 >> );
tmp++;
resultsize += ;
}
p++;
}
/*不考虑结束符,如果考虑则打开此段!
*tmp = '/0';
tmp++;
*tmp = '/0';
resultsize += 2;
*/
return resultsize;
}

上面代码是通是UTF-8转Unicode来获取字符数量。当输入字符数量过多时,可能字节大小会超过声明的char数组大小,导致出现越界情况,程序崩溃。

解决方法一:根据限定字符数量,将char数组大小声明为最大数量,来避免越界情况出生

解决方法二:定义一个私有变量unicodeCount(名字随意取)来记录输入字符的总数量。由于onTextFieldInsertText,onTextFieldDeleteBackward这两个方法都是在我们输入一个完整字符或者减去一个完整字符时调用一次,所以将unicodeCount++放入onTextFieldInsertText,将unicodeCount--放入onTextFieldDeleteBackward中,可以完成输入字符数量的保存。这样就可以免去UTF-8转Unicode的操作,完全避免越界情况产生,也提高了效率

效率方面尚未优化,请参考自行优化,只提供一个解决思路

接下来将会写一篇光于cocos2d-普通文本显示框,不支持富文本,主要提供自动换行解决思路,以解决当前CCLabelTTF自动换行Bug的替代方案

cocos2d-x 聊天输入框实现的更多相关文章

  1. apicloud 聊天输入框模块UIChatBox

    点击链接查看详情 https://docs.apicloud.com/Client-API/UI-Layout/UIChatBox 模板中包括,聊天输入框,表情,发送图片,还有拍照,录音,其中也可以放 ...

  2. 五、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊天APP,支持各类消息收发,音视频通话,附vue实现源码(已开源)-聊天输入框的实现

    会话好友列表的实现 1.项目引言 2.腾讯云后台配置TXIM 3.配置项目并实现IM登录 4.会话好友列表的实现 5.聊天输入框的实现 6.聊天界面容器的实现 7.聊天消息项的实现 8.聊天输入框扩展 ...

  3. 八、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊天APP,支持各类消息收发,音视频通话,附vue实现源码(已开源)-聊天输入框扩展面板的实现

    聊天输入框扩展面板的实现 1.项目引言 2.腾讯云后台配置TXIM 3.配置项目并实现IM登录 4.会话好友列表的实现 5.聊天输入框的实现 6.聊天界面容器的实现 7.聊天消息项的实现 8.聊天输入 ...

  4. 获得QQ聊天输入框中的内容

    // 首先得到输入框的句柄.通过spy++这类工具分析,聊天窗体的类名为“#32770”// 但当前系统里不只一个类名为“#32770”的窗体,这就需要全体遍历一次.// 类名为“#32770”标题含 ...

  5. AS3聊天单行输入框图文混排完美实现

    几年前刚毕业.第一个游戏模块做的就是聊天.到如今.几个游戏写过几次聊天模块. 之前在4399做的<幻龙骑士>(又名<神骑士>),还有上周六刚上线的<疯狂的子弹>, ...

  6. 使用Servlet和JSP实现一个简单的Web聊天室系统

    1 问题描述                                                利用Java EE相关技术实现一个简单的Web聊天室系统,具体要求如下. (1)编写一个登录 ...

  7. iOS开发之聊天模块--内容保存逻辑实现

    需求详解: 在实际开发中,有可能是在后期优化的时候,会有这么需要优化的需求:聊天输入框保存之前输入的文本,提高用户的良好体验. 在聊天模块中,用户可能会在输入框输入若干字符,但是没有点击发送就点击退出 ...

  8. ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(七)之 图文,附件消息(2016-05-05 12:13)

    上一篇介绍了加好友的流程,这里不再赘述,不过之前的聊天只能发送普通文字,那么本篇就教你如何实现发送附件和图片消息.我们先对功能进行分析: 发送图片,附件,需要实现上传图片和附件的功能. textare ...

  9. websocket简单实现聊天

    1.多人聊天 from geventwebsocket.handler import WebSocketHandler # 请求处理WSGI HTTP from geventwebsocket.ser ...

随机推荐

  1. mongoDB入门必读

    一.概述 MongoDB是一个基于分布式文件存储的数据库开源项目. 由C++语言编写,旨在为WEB应用提供可护展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品. ...

  2. PHP使用Mysql事务实例解析

    <?php //数据库连接 $conn = mysql_connect('localhost', 'root', ''); mysql_select_db('test', $conn); mys ...

  3. struts2 package元素配置

    package 元素的所有属性及对应功能: Attribute Required Description name yes key to for other packages to reference ...

  4. [转]jBoss事务控制

    转自:http://blog.csdn.net/trendgrucee/article/details/8545512   一.基础知识 1.JTA,即Java Transaction API,译为J ...

  5. Java传参那些事!

    刚刚学习java传参的时候很纠结,也非常的不理解!课本上的“按值传递”和“按址传递”搞的自己是一头雾水,后来写的项目多了,自然就明白了! 现在写传参几乎就是条件反射一般——“秒成”,分享当初自己为此写 ...

  6. 【转】Tomcat配置文件入门

    Tomcat 基本配置 tomcat读取配置文件 首先简单说一下tomcat是如何读取配置文件的.tomcat在启动时,首先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOM ...

  7. CSS和SVG中的剪切——clip-path属性和<clipPath>元素

    剪切是什么 剪切是一个图形化操作,你可以部分或者完全隐藏一个元素.被剪切的元素可以是一个容器也可以是一个图像元素.元素的哪些部分显示或隐藏是由剪切的路径来决定的. 剪切路径定义了一个区域,在这个区域内 ...

  8. How to Convert a Date Time to “X minutes ago” in C# z

    http://www.codeproject.com/Articles/770323/How-to-Convert-a-Date-Time-to-X-minutes-ago-in-Csh In one ...

  9. HDU4865 Prince and Princess 强连通分量+二分图判定

    这个题就是建图费点劲,别的和我上一篇博客一样 然后,参考思路请戳这里http://www.cnblogs.com/wally/archive/2013/09/12/3317883.html 补充:这个 ...

  10. HDU5593 ZYB's Tree 树形DP +分治

    感觉其实就是树分治,一次BC的题,感觉这次题目质量比较高,仅代表蒟蒻的看法 一次DFS获取每个点到子树的距离不大于K的点的个数, 然后一遍BFS获取从每个点父亲不大于K的的个数,层层扩展,还是想说 其 ...