无法在RichEdit中保留换行符

时间:2013-03-07 05:08:31

标签: c++ winapi richedit

我在从字符串内的RichEdit控件保留新闻行时遇到问题。 我正在做的是:

  1. 从RichEdit控件获取文本
  2. 拆分由空格分隔的所有内容
  3. 添加一些RTF格式
  4. “Fuse”字样一起回来
  5. 发送文字进行控制
  6. 我不确定是什么原因导致这一点所以这里是最相关的部分:

    int RichEdit::GetTextLength() const
    {
        GETTEXTLENGTHEX len;
        len.codepage = 1200;
        len.flags = GTL_NUMBYTES;
        return (int)SendMessage(this->handle, EM_GETTEXTLENGTHEX, (WPARAM)&len, 0) + 1;
    }
    
    tstring RichEdit::GetText() const
    {
        auto len = this->GetTextLength();
        GETTEXTEX str;
    
        TCHAR* tmp = new TCHAR[len];
        str.cb = len;
        str.flags = GT_USECRLF;
        str.codepage = 1200;
    
    
        str.lpDefaultChar = NULL;
            str.lpUsedDefChar = NULL;
    
            (void)SendMessage(this->handle, EM_GETTEXTEX, (WPARAM)&str, (LPARAM)tmp);
    
            tstring ret(tmp);
    
            delete[] tmp;
            return ret;
        }
    
    void RichEdit::SetRtfText(const tstring& text, int flags)
        {
            DWORD WideLength = text.length();
            DWORD Length     = WideLength * 4;
            PSTR Utf8        = (PSTR)malloc(Length);
    
            int ReturnedLength = WideCharToMultiByte(CP_UTF8,
                0,
                text.c_str(),
                WideLength-1,
                Utf8,
                Length-1,
                NULL,
                NULL);
    
            if (ReturnedLength)
                Utf8[ReturnedLength] = 0;
    
            SETTEXTEX st = {0};
            st.flags = flags;
            st.codepage = CP_UTF8;
            (void)SendMessage(this->handle, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)Utf8 );
    
            free(Utf8);
        }
    
    void split ( tstring input , tstring split_id, std::vector<std::pair<tstring,bool>>& res ) {
        std::vector<std::pair<tstring,bool>> result;
        int i = 0;
        bool add;
        tstring temp;
        std::wstringstream ss;
        size_t found;
        tstring real;
        int r = 0;
        while ( i != input.length() ) 
        {
            add = false;
            ss << input.at(i);
            temp = ss.str();
    
            found = temp.find(split_id);
            if ( found != tstring::npos ) 
            {
                add = true;
                real.append ( temp , 0 , found );
            } else if ( r > 0 &&  ( i+1 ) == input.length() ) 
            {
                add = true;
                real.append ( temp , 0 , found );
            }
            if ( add ) 
            {
                result.emplace_back(std::make_pair(real,false));
                ss.str(tstring());
                ss.clear();
                temp.clear();
                real.clear();
                r = 0;
            }
            i++;
            r++;
        }
        res = result;
    }
    

    ps:tstring只是std :: wstring / std :: string

    的typedef

    如何保留换行符?

1 个答案:

答案 0 :(得分:1)

您的代码存在很多问题。

您的代码基于TCHAR,但您实际上并未使用TCHAR正确检索/设置RTF数据。

在检索文本时,您正在将换行符规范化为CRLF,但在检索文本长度时,您没有进行相同的规范化,因此它们将彼此不同步。

您正在使用UTF-8向RichEdit写入数据,但RTF是一种基于ASCII的格式,它使用Unicode数据的转义序列。如果您要将数据检索为Unicode,您也可以使用Unicode编写它,并确保您正确地开始使用所有这些。让RichEdit控件为您处理Unicode。

您使用WideCharToMultiByte()是错误的。你不应该从字符串长度中减去-1。您可能尝试考虑空终止符,但长度值不包括空终止符。如果您要坚持使用UTF-8,那么您应该使用WideCharToMultiByte()计算正确的UTF-8长度而不是硬编码。

int Length = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), text.length(), NULL, 0, NULL, NULL);
char Utf8 = new char[Length+1];
WideCharToMultiByte(CP_UTF8, 0, text.c_str(), text.length(), Utf8, Length, NULL, NULL);
Utf8[Length] = 0;
...
delete[] Utf8;

话虽如此,如果你要坚持使用TCHAR,那么试试这个:

#ifdef UNICODE
#define RTFCodePage 1200
#else
#define RTFCodePage CP_ACP
#endif

int RichEdit::GetTextLength() const
{
    GETTEXTLENGTHEX len = {0};
    len.codepage = RTFCodePage;
    len.flags = GTL_NUMCHARS | GTL_USECRLF;
    return SendMessage(this->handle, EM_GETTEXTLENGTHEX, (WPARAM)&len, 0);
}

tstring RichEdit::GetText() const
{
    int len = this->GetTextLength() + 1;

    GETTEXTEX str = {0};
    str.cb = len * sizeof(TCHAR);
    str.flags = GT_USECRLF;
    str.codepage = RTFCodePage;

    vector<TCHAR> tmp(len);
    len = SendMessage(this->handle, EM_GETTEXTEX, (WPARAM)&str, (LPARAM)&tmp[0]);

    return tstring(&tmp[0], len-1);
}

void RichEdit::SetRtfText(const tstring& text, int flags)
{
    SETTEXTEX st = {0};
    st.flags = flags;
    st.codepage = RTFCodePage;

    #ifdef UNICODE
    st.flags |= ST_UNICODE;
    #endif

    SendMessage(this->handle, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)text.c_str());
}

最好放弃TCHAR并将Unicode用于所有内容:

int RichEdit::GetTextLength() const
{
    GETTEXTLENGTHEX len = {0};
    len.codepage = 1200;
    len.flags = GTL_NUMCHARS | GTL_USECRLF;
    return SendMessage(this->handle, EM_GETTEXTLENGTHEX, (WPARAM)&len, 0);
}

wstring RichEdit::GetText() const
{
    int len = this->GetTextLength() + 1;

    GETTEXTEX str = {0};
    str.cb = len * sizeof(WCHAR);
    str.flags = GT_USECRLF;
    str.codepage = 1200;

    vector<WCHAR> tmp(len);
    len = SendMessage(this->handle, EM_GETTEXTEX, (WPARAM)&str, (LPARAM)&tmp[0]);

    return wstring(tmp, len-1);
}

void RichEdit::SetRtfText(const wstring& text, int flags)
{
    SETTEXTEX st = {0};
    st.flags = flags | ST_UNICODE;
    st.codepage = 1200;

    SendMessage(this->handle, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)text.c_str());
}

更新:如果您必须返回UTF-8查看EM_SETTEXTEX消息,请尝试以下操作:

void RichEdit::SetRtfText(const tstring& text, int flags)
{
    string Utf8;
    int Length;

    #ifdef UNICODE

    Length = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), text.length(), NULL, 0, NULL, NULL);
    if (Length > 0)
    {
        Utf8.resize(Length);
        WideCharToMultiByte(CP_UTF8, 0, text.c_str(), text.length(), &Utf8[0], Length, NULL, NULL);
    }

    #else

    Length = MultiByteToWideChar(CP_ACP, 0, text.c_str(), text.length(), NULL, 0);
    if (Length > 0)
    {
        vector<WCHAR> tmp(Length);
        MultiByteToWideChar(CP_ACP, 0, text.c_str(), text.length(), &tmp[0], Length);

        Length = WideCharToMultiByte(CP_UTF8, 0, tmp.c_str(), tmp.length(), NULL, 0, NULL, NULL);
        if (Length > 0)
        {
            Utf8.resize(Length);
            WideCharToMultiByte(CP_UTF8, 0, tmp.c_str(), tmp.length(), &Utf8[0], Length, NULL, NULL);
        }
    }

    #endif

    SETTEXTEX st = {0};
    st.flags = flags & ~ST_UNICODE;
    st.codepage = CP_UTF8;
    SendMessage(this->handle, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)Utf8.c_str());
}