CEGUIEditBox : 获得准确的字符长度,看我给CEGUIEditBox动手术

来源:互联网 发布:尼加拉瓜运河 知乎 编辑:程序博客网 时间:2024/06/09 19:27

 天龙八部的底层是用0.4.0版本的cegui做的,种种控件已经做得很完整了。

天龙八部的代码拯救了大部分无家可归的程序员。

CEGUIEditbox控件已经为我们做好了这个最大长度限制的属性 MaxTextLength

我们打开天龙八部的logon.layout.xml文件 虽然是武侠世界的源码但是我觉得已经做很完整了,至少学习足够了

 .....

    <Window Type="TLBB_EditBoxNormal" Name="LogOn_ID">
     <Property Name="AbsolutePosition" Value="x:33.000000 y:60.000000" />
     <Property Name="AbsoluteSize" Value="w:100.000000 h:19.000000" />
     <Property Name="Text" Value="请输入账号" />
     <Event Name="TextAccepted" Function="Logon_LogOn_ID_Return();" /> 文字注入捕获 Lua处理函数 Logon_LogOn_ID_Return()

     <Event Name="TabPressed" Function="Logon_ID_TabPressed();" />TAB键捕获Lua处理函数 Logon_ID_TabPressed()
     <Event Name="MouseEnter" Function="LogOn_ID_MouseEnter();" />鼠标进入捕获Lua处理函数 LogOn_ID_MouseEnter()
     <Event Name="MouseLeave" Function="LogOn_MouseLeave();" />鼠标移出捕获Lua处理函数 ="LogOn_MouseLeave()
     <Event Name="Activated" Function="LogOn_LogonID_Active();" />输入框激活捕获Lua处理函数 LogOn_LogonID_Active()

     <Event Name="Deactivated" Function="LogOn_LogonID_Deactivated();" />输入框冻结捕获Lua处理函数 LogOn_LogonID_Deactivated()
     <Property Name="MaxTextLength" Value="32" />
    </Window>

.....

<Property Name="MaxTextLength" Value="32" />

有这个属性在我们能够很清楚的了解一个事情,LogOn_ID里面最大的输入串长度是32字节;

如果我们的cegui版本没有动过手术的话,那么MaxTextLength的数值必然是32个字符,或者32个汉字。至少我用的版本0.75是如此。

那么如何获得到精准的字符长度呢?比如如果我的输入框就是想让中英文结合,此时我想让玩家输入的数据只有32字节长度,怎么办。

字符占用一个字节,汉字占用2个字节;从高中的计算机教材中就能了解这些,

接下来如何实现:

 

来看下天龙八部是怎么处理字符串长度的问题的吧cegui0.75和cegui0.40版本有本质上的不同,至于不同点是什么,诶引用句广告词:蚁力神,谁用谁知道。

最大的区别就是0.6以后cegui版本彻底把逻辑和渲染分开,0.75开始支持3d旋转了。就是一个界面可以有360的角度变化了,效率提高了一大截 XXXX

诶。言归正传,他们的区别远不止这些;说正事 

我们翻阅下cegui的EditBox实现部分在获得文字注入消息的时候他会激活这个函数

当然天龙版本是0.40版本激活 addCharater()0.75版本触发的函数是onCharacter()

虽然名字换了,但大体是换汤不换药。功能不会换。

0.75 版本

onCharacter()

{

        // backup current text
        String tmp(getText());
        tmp.erase(getSelectionStartIndex(), getSelectionLength());

        // if there is room
        if (tmp.length() < d_maxTextLen)

        {     。。。。。。。。。。。。。。};

}

 为何新的0.75只和字符数量杠上了,元凶在这红色代码上面接下来直接看天龙代码是如何改的

 天龙的0.40是这样的函数addCharater()是接收字符的地方里面有这句话

addCharater()

{    

     。。。。。。

      if (tmp.mbcs_length() + str.mbcs_length() <= d_maxTextLen)

     。。。。。。

}

好找了,打开天龙的CEGUIString.h我们看下这个函数的实现

 // return number of code units in a null terminated string

//天龙八部的实现

//应该是这样的,天龙八部的实现方法是有错的

// 这里我更正下当初自己的错误观点以下的实现才是真正的‘可视字符串实现’

 size_type mbcs_length(void) const
 {
  const char* code = c_str();
  const utf8* buf = build_utf8_buff();
  size_type len = d_encodedbuff;

  utf8 tcp;
  size_type count = 0;

  while (len--)
  {
   tcp = *buf++;
   ++count;

   if (tcp < 0x80)
   {
   }
   else if (tcp < 0xE0)
   {
    --len;
    ++buf;
    ++count;
   }
   else if (tcp < 0xF0)
   {
    len -= 2;
    buf += 2;
    ++count;
   }
   else
   {
    len -= 2;
    buf += 3;
    ++count;
   }

  }

  return --count;
 }

 

 变动下这里

0.75 版本 EdibBox:::onCharacter()

{

      。。。。。。         

      if (tmp.mbcs_length() < d_maxTextLen)

      。。。。。。

}

ok了,我的demo已经成功切断多余的字符完成了这个小手术075也有这个功能了

如果觉得这个功能直接改不太好,那么完全可以给EditBox再增加个新属性

什么时候想用了,让这个属性打开就成了

说做就做;

在CEGUIEditBoxProperty.h文件中添加
class ActiveByteLenth: public Property
{
public:
 ActiveByteLenth() : Property(
  "ActiveByteLenth",
  "False."// 这个属性默认为关闭状态否则麻烦大大

 {}

 String get(const PropertyReceiver* receiver) const;
 void set(PropertyReceiver* receiver, const String& value);
};

CEGUIEditBoxProperty.cpp中添加

void MaskCodepoint::set(PropertyReceiver* receiver, const String& value)
{
 static_cast<Editbox*>(receiver)->setActiveByteLenth(PropertyHelper::stringToBool(value));
}


String ValidationString::get(const PropertyReceiver* receiver) const
{
 return PropertyHelper::boolToString(static_cast<const Editbox*>(receiver)->isActiveByteLenth());

 

在CEGUIEditbox.h中添加

bool  b_activeBytelenth;//  记得给这个值初始化否则debug和release下面默认值的结果是相反的

void setActiveByteLenth(bool setting)   {b_activeBytelenth = setting;};

bool isActiveByteLenth(void)  const      {return   b_activeBytelenth;};

 static EditboxProperties::ActiveByteLenth     d_activeByteLenthProperty;

 

在CEGUIEditbox..cpp中添加

EditboxProperties::ActiveByteLenth     Editbox::d_activeByteLenthProperty;
void Editbox::addEditboxProperties(void)
{
 CEGUI_START_ADD_STATICPROPERTY( Editbox );
    CEGUI_ADD_STATICPROPERTY( &d_activeByteLenthProperty); //包含到控件中如此属性就和变量关联起来了

 CEGUI_END_ADD_STATICPROPERTY

}

然后在函数onCharacter中可以这样写

EdibBox:::onCharacter()

{

       。。。。。。

        int     tmplenth =   b_activeBytelenth  ?   tmp.mbcs_length()tmp.length()
        if   (tmplenth   <    d_maxTextLen)

        。。。。。。

}

如此我的0.75就拥有了新的属性成员ActiveByteLenth

    <Window Type="TLBB_EditBoxNormal" Name="LogOn_ID">
     <Property Name="AbsolutePosition" Value="x:33.000000 y:60.000000" />
     <Property Name="AbsoluteSize" Value="w:100.000000 h:19.000000" />
     <Property Name="Text" Value="请输入账号" />        

     <Property Name="ActiveByteLenth" Value="True" />     

     <Property Name="MaxTextLength" Value="32" />

  </Window>
如此我就可以在layout.xml文件中轻而易举的打开和关闭这个属性什么时候想用什么时候讲ActiveByteLenth设置成True就可以了,其他的控件依旧保持原有属性

扩展了一个属性比改掉一个接口要可取些