CEGUI::String类分析

简介: CEGUI::String类算是一个不错的类,但是说实话,这个类让非英文国度的IT们不是很舒服。比如,自我们学习C++编程以来,我们一直使用这样的输出语句: std::cout

CEGUI::String类算是一个不错的类,但是说实话,这个类让非英文国度的IT们不是很舒服。比如,自我们学习C++编程以来,我们一直使用这样的输出语句:

std::cout << "名字: " << szName << std::endl;

其中"名字:"使用的是多字节编码(ASCII编码的扩充版本)。我们的控制台能正确显示这些中文文本。但是当我们初次了解并使用CEGUI的时候,却无法使用这样简单的功能:

CEGUI::String strName = "徐杰";
pNameWindow->setText( strName );

不是说编译不过,而是显示不正确。求其根源有两个原因:

  1. CEGUI 使用 utf32 编码方案,这个并不重要。重要的是 CEGUI::String 如何将 const char* 这样参数转换成其内部编码方式。只要转换正确,CEGUI会按照自己的方式,将utf32 编码方案的文本显示出来。但不幸的是,eddy博士的团队并不认为 const char* 会指向非英文字符串,所以 CEGUI::String 接受 const char* 的构造函数,根本就没有进行多字节编码到 utf32 编码的转换。

  2. 其次,即使我们将多字节编码正确转换成了 utf32 编码,传给了CEGUI::String,我们也无法让空间显示出中文。这个问题主要是字体文件的问题,正确的字符编码必须使用正确字体文件,才能正确显示出中文。(一开始,我还以为是CEGUI::String本身的问题,后来到网上查了查,CEGUI::String的utf8构造函数是没有问题的,只是需要正确的字体文件)

我们根据这两个问题,分别给出解决方案:

  1. CEGUI::String 接受几种字符串类型,通过查看源码CEGUI::String只支持其他三种字符串类型:

    String(const char* chars, size_type chars_len)
    	{
    		init();
    		assign(chars, chars_len);
    	}
    String(const std::string& std_str, size_type str_idx, size_type str_num = npos)
    	{
    		init();
    		assign(std_str, str_idx, str_num);
    	}
    String(const utf8* utf8_str, size_type chars_len)
    	{
    		init();
    		assign(utf8_str, chars_len);
    	}
    第一种和第二种其实是一样的,std::string只不过是 const char* 的封装类,内部还是使用的多字节编码。第三种是接受一个utf8编码的字符串。之前我们讲过,CEGUI::String 根本不对 const char* 进行适当的编码转换,所以如果我们想传入中文文本,那么,我们唯一的出路是使用 utf8 编码的字符串。这样我们就需要构造 utf8 字符串了。Window SDK有响应的函数可以帮助我们完成多字节编码到utf8编码的转换。下面是我写的转换函数:
    #define MB2UTF8( str ) ( const CEGUI::utf8* )( MultiByteToUtf8( ( str ) ).c_str() )
    
    std::string MultiByteToUtf8( const char* pszMultiByte )
    {
        std::string strUtf8;
    
        if( NULL == pszMultiByte )
        {
            return strUtf8;
        }
    
        int iNumCharacter = 0;
    
        //convert from MultiByte to WideChar
        std::wstring wcsText;
        iNumCharacter = MultiByteToWideChar( CP_ACP, 0, pszMultiByte, -1, NULL, 0 );
        wcsText.resize( iNumCharacter + 1 );//addition 1 for '\0'
    
        MultiByteToWideChar( CP_ACP, 0, pszMultiByte, -1, &wcsText[ 0 ], iNumCharacter );
    
        //convert from WideChar to utf8
        iNumCharacter = WideCharToMultiByte( CP_UTF8, 0, &wcsText[ 0 ], -1, NULL, 0, NULL, NULL );
        strUtf8.resize( iNumCharacter + 1 );
        WideCharToMultiByte( CP_UTF8, 0, &wcsText[ 0 ], -1, &strUtf8[ 0 ], iNumCharacter, NULL, NULL );
    
        return strUtf8;
    }
    
    void setWindowText( CEGUI::Window* pWindow, const char* pszText )
    {
        if( NULL == pWindow || NULL == pszText )
        {
            return;
        }
    
        pWindow->setText( MB2UTF8( pszText ) );
    }
    
  2. 给出正确的字体文件。

    1. 首先到 C:\WINDOWS\Fonts 路径下找到一个带有中文字符的字体文件 ”simhei",拷贝一下,然后放到 CEGUI SDK 的 datafiles\fonts 路径下。
    2. 复制 CEGUI SDK 的 datafiles\fonts 下的一个.font文本,然后粘贴一下(出来一个该文件的副本),更改文件名为simhei.font。然后用写字板或者记事本打开,如下文本:
      <?xml version="1.0" ?>
      <Font Name="Batang-26" Filename="batang.ttf" Type="FreeType" Size="26" NativeHorzRes="1024" NativeVertRes="768" AutoScaled="true"/>
      
      修改 Name(代表程序中使用什么名字表示该字体) 和 Filename(该字体对应的字体文件名)字段:
      <?xml version="1.0" ?>
      <Font Name="simhei" Filename="simhei.ttf" Type="FreeType" Size="26" NativeHorzRes="1024" NativeVertRes="768" AutoScaled="true"/>
      
    3. 修改对应的.scheme文件,打开TaharezLook.scheme文件,将
      <Font Filename="DejaVuSans-10.font" />
      修改为:
      <Font Filename="simhei.font" />

最后还是建议,直接修改CEGUI::String的源码,将ASCII正确地转换成 utf32 编码,这样效率更高一点,使用也更加舒服。例如,添加下列代码到CEGUI::String类中可实现直接传递宽字符:

    String( const wchar_t* utf16 )
    {
        init();
        assign( utf16 );
    }

    String& assign( const wchar_t* utf16 )
    {
        if( NULL == utf16 )
        {
            return *this;
        }

        int iNumCharacter = wcslen( utf16 );

        grow( iNumCharacter );

        utf32* pData = ptr();
        for( int i = 0; i < iNumCharacter; ++i )
        {
            pData[ i ] = utf16[ i ];
        }

        setlen( iNumCharacter );

        return *this;
    }
因为utf16绝大部分是utf32的子集,所以可以直接赋值(至少对于汉字来说可以)。

更多关于字符编码的问题,网友可以查看本人博客:彻底搞懂字符编码(unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian...)

相关文章
|
23天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
46 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
20天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
20 2
|
22天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1
|
25天前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
48 4
|
30天前
|
存储 安全 Java
【一步一步了解Java系列】:认识String类
【一步一步了解Java系列】:认识String类
24 2
|
1月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
33 4
|
1月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
59 2
|
1月前
|
C语言 C++
C++番外篇——string类的实现
C++番外篇——string类的实现
19 0
|
1月前
|
C++ 容器
C++入门7——string类的使用-2
C++入门7——string类的使用-2
20 0
|
1月前
|
C语言 C++ 容器
C++入门7——string类的使用-1
C++入门7——string类的使用-1
21 0

热门文章

最新文章