当前位置:C++技术网 > 资讯 > 完美记事项目:1 CRichEditCtrl之GetLine成员函数深入详细分析

完美记事项目:1 CRichEditCtrl之GetLine成员函数深入详细分析

更新时间:2015-06-26 12:19:01浏览次数:1+次

int GetLine( int nIndex, LPTSTR lpszBuffer ) const;
 int GetLine( int nIndex, LPTSTR lpszBuffer, int nMaxLength ) const;
 
    此函数两有两个重载版本。此函数用于获取富文本框控件中指定行的文字。MSDN中对此函数的说明太少,很多东西没有说清楚,给出的代码示例是第二个版本的,第二个版本使用上,不存在问题。但是第一个版本会出现获取不到文字的情况。因为仅仅看MSDN的这个函数说明,根本就看不懂。下面我来给大家讲解一下。

    返回值是实际返回到第二个参数给出的缓冲的字符数。

    第一个参数是行号,从0开始。确定行号是通过换行符的。但是有一点特别需要注意的就是,文字自动换行后,富文本框会给文本自动添加一个换行符。也就是说,一行的结尾是在一行结束或者中间手动换行作为结尾。而我们通常以为自动换行不会产生换行符,其实会自动添加的。所以在以行处理时,要注意此问题。而富文本框调整大小后,这个换行符应该会自动出去,这是控件自动做的。

    第二个参数是接受获取文本的缓冲。

    第三个参数是要接受的最大字符数。如果字符数为0,则获取不到文字。如果使用第二个版本,只要在第三个参数传入大于零的数字,就可以了。使用没有什么问题。但是,如果使用第一个版本,就容易出问题了。

    很多人并没有真正看懂第一个版本的意思,MSDN也没有说的很明白。第一个版本的缓冲有两个功能,第一个就是接受字符,这个都理解。第二个说开始两个字节即一个字,记录获取字符的最大字符数。这一点很多人都不明白,也就发生了说获取不到字符的情况。这个我开始也是感觉很奇怪。第二个参数的第二个功能就是用来传递要获取的最大字符数。也就是说,在获取字符之前,给缓冲的开始两个字节设置一个值,用来表示要接受的最大字符数。两个字节拼成一个字,来表示。这个数据传递进去后,使用完后就会被获取到的字符覆盖,因此最后,缓冲区只有字符。而在第二个版本的GetLine中,使用了第三个参数来传递最大字符数,因此不用这么麻烦。我想说一句,这样设计是为了缩短参数,然而却让使用非常的麻烦。所以平时就只使用第二个版本就行了。因为第二个版本会自动处理换行符的问题,我们获取到的就不会存在换行符,只是最后返回的字符连空字符也没有。但是使用CString会自动添加结尾的空字符。所以也不用处理结尾空字符的问题。 

第二个版本的代码示例如下:
int len = m_rt.LineLength(0);// - 获取0行字符数
CString str;
m_rt.GetLine(0,str.GetBuffer(len),len);// - 获取0行的字符
str.ReleaseBuffer(len);
MessageBox(str);

代码说明:
1.str调用GetBuffer传入缓冲地址,此时相当于把CString对象中的缓冲打开了。并且使用指定的字符大小打开的。此时不能调用CString的其他成员函数,因为结果是不确定的。只有调用ReleaseBuffer后,才可以正常的调用成员函数。
2.GetBuffer传入多大参数,ReleaseBuffer最好传入多大的参数,保持一致,除非你很清楚内部的原理。

最麻烦的部分就是第一个版本,下面重点讲讲这个版本的使用,也可以看清楚这个函数的实现原理。  

        int len = m_rt.LineLength(0)*sizeof(TCHAR);
        if (!pBuf)
        {
            pBuf = new BYTE[len+sizeof(TCHAR)];
            memset(pBuf,0,len+sizeof(TCHAR));
        }
        pBuf[0]=len;// - 设置要接受的字符数的低字节
        pBuf[1]=0;// - 设置要接受的字符数的高字节
        m_rt.GetLine(0,(LPTSTR)pBuf);// - 获取0行的文本
        pBuf[len]=0;// - 结尾设置0,设置空字符
        if (sizeof(TCHAR)==2)pBuf[len+1]=0;// - 如果是宽字符,则再清零字节
        MessageBox((LPTSTR)pBuf);// - 必须在释放内存之前执行
        delete [] pBuf;// - 使用完一定要释放,不能漏了
        pBuf = NULL;   // - 置空指针,不能漏了


此版本便于观察内存变化,也给大家提供一种使用方法。

给pBuf动态分配一块内存后,然后清空内存,内存结果如下:

在文本框中输入abcd,GetLine后,内存如下:

    因为是宽字符,富文本框在最后两个字节中,添加了一个换行符。0x0d就是换行符的ANSII码。通过此种方式,我们需要自己处理这个换行符。所以代码在后面,要将最后的换行符替换成空字符即0.分配内存多分配一个或者两个(宽字符),以便最后自己给最后的结尾设置成空字符,形成字符串,方便显示。
     这里要注意的一点,pBuf[0]=len;这一句是不能少的。这就相当于在GetLine的二个版本的函数中传入一个最大字符数一样。如果不设置,默认的就是0,如果是0,那么就表示我们要获取的最大字符数为0,因此就获取不到字符。所以,这里必须设置,一般都是设置成调用LineLenght成员函数返回的一行的字符数。而实际上,这种用法是非常麻烦的,如果不是必要,不要这样使用。下面给一个方便使用的代码用法。 
第一个版本使用代码示例:

int len = m_rt.LineLength(0);
CString str;
str.GetBufferSetLength(len);// - 设置字符串缓冲大小为字符大小
str.SetAt(0,len);// - 给低字节设置需要获取的字符大小
m_rt.GetLine(0,str.GetBuffer(len));// - 获取一行字符
str.ReleaseBuffer(len);
MessageBox(str);


代码说明:
1.设置要获取的字符最大大小需要注意的一点就是,如果字符数超过了一个字节表示的大小,则需要设置缓冲区第二个字节,与第一个字节组合成一个最大字符数。同样是调用SetAt函数执行。
2.上面说的设置大小的,对于讲解原理配图的版本也是一样的。
3.SetAt是CString用来设置缓冲元素赋值用的,直接使用[]下标只能取值,不能赋值。
4.一个字即两个字节,而第二个版本的GetLine第三个参数是int 类型,即四个字节,因此能够表示最大的字符数也比第一个版本多,所以,这也是推荐使用第二个版本的原因之一。