转自: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. Where is Vasya?

    Where is Vasya? Vasya stands in line with number of people p (including Vasya), but he doesn't know ...

  2. 谈谈Runtime类中的freeMemory,totalMemory,maxMemory等几个方法

    最近在网上看到一些人讨论到java.lang.Runtime类中的freeMemory(),totalMemory(),maxMemory ()这几个方法的一些问题,很多人感到很疑惑,为什么,在jav ...

  3. UVa 11440 (欧拉函数) Help Tomisu

    题意: 给出N和M,统计区间x ∈ [2, N!],x满足所有素因子都大于M的x的个数. 分析: 首先将问题转化一下,所有素因子都大于M 等价于 这个数与M!互素 对于k大于M!,k与M!互素等价于 ...

  4. tyvj1519博彩游戏

    博彩游戏 From admin 背景 Background Bob最近迷上了一个博彩游戏…… 描述 Description 这个游戏的规则是这样的:每花一块钱可以得到一个随机数R,花上N块钱就可以得到 ...

  5. JavaEE基本了解

    1.  为什么需要JavaEE 我们编写的JSP代码中,由于大量的显示代码和业务逻辑混淆在一起,彼此嵌套,不利于程序的维护和扩展.当业务需求发生变化的时候,对于程序员和美工都是一个很重的负担. 为了程 ...

  6. android 打包签名

    1.Eclipse工程中右键工程,弹出选项中选择 android工具 → 生成签名应用包 2.选择需要打包的android项目工程 3.如果已有私钥文件,选择私钥文件 输入密码,如果没有私钥文件见第6 ...

  7. HDU 1394-Minimum Inversion Number(BIT)

    题意: 给你n个数字的序列 每次把第一个数字放到最后 得到一个新序列 一共有n个序列求这些序列中哪个序列含最小的总的逆序数 (输出最小总逆序数) 分析: 用BIT求出初始各数的逆序数,第一个数放最后它 ...

  8. SGU 390-Tickets(数位dp)

    题意:有标号l-r的票,要给路人发,当给的票的编号的各数位的总和(可能一个人多张票)不小k时,才开始发给下一个人,求能发多少人. 分析:这个题挺难想的,参考了一下题解,dp[i][sum][left] ...

  9. Codeforces 633D Fibonacci-ish 暴力

    题意:1000个元素,每个元素的大小-1e9<=a[i]<=1e9,然后让你重新安排这些元素的位置 获得最长的前缀斐波那契数列 分析:枚举第一个元素和第二个元素,因为在题目元素的范围内,最 ...

  10. Serv-U搭建FTP服务器

    1.打开软件,勾选start automatically 2.点击domain,新建domain 3.依次输入IP.端口号.域名.域名类型 完成后的样子 4.右键单击Users,新建用户.依次输入用户 ...