RichEdit 性能优化
一, 问题描述
需要显示 TLV ( Type-length-value )数据,并且使用不同的颜色来显示 Tag , Length , Value 三类数据,以示区别。按照 16 进制显示,并且字节间用空白分割。如 AB CD 01 0A 等。
有可能显示几十 M 规模的二进制数据。
显示数据时, UI 应该能够响应用户操作。
因为 RichEdit 可以显示 RTF 文档,可以任意控制文字的颜色,大小,风格等。所以决定使用 RichEdit 控件来实现此功能。
二, 直接 Insert 数据
根据 TLV 规则,向 RichEdit 逐个项目添加数据。
Foreach tlv
设定 RichEdit 的文字颜色为 Tag 色
插入 Tag 数据
设定 RichEdit 的文字颜色为 Length 色
插入 Length 数据
设定 RichEdit 的文字颜色为 Value 色
插入 Value 数据
通过 CRichEditCtrl 的 SetSelectionCharFormat 函数来设定文字颜色。
通过 CRichEditCtrl 的 SetSel( -1 , -1 ) , ReplaceSel 函数来插入数据。需要注意的是,应该首先设置文字颜色,然后才能插入数据。
效果:功能能够实现,但是速度特别慢。不可接受。因为大量调用了 SetSel 和 SetSelectionCharFormat ,而这两个函数都比较慢。
改善:在 foreach tlv 过程中,应该关闭 RichEdit 的 Redraw 功能,一方面提高了性能,另一方面防止了 RichEdit 控件数据的闪烁。
三, 使用 StreamIn
浏览了 RichEdit 控件的接口时,发现了如下方法。
long StreamIn(
int nFormat,
EDITSTREAM& es
);
该函数可以从 Stream 中读取数据并放入 RichEdit 控件中。
nFormat 有两种可能的值:
SF_TEXT 表示纯文本
SF_RTF 表示 RTF 文档,该文档可以设置颜色,大小等信息。
如果使用该功能的话,必须了解 RTF 文档的格式,最新的 Rich Text Format (RTF) Specification, version 1.9.1 的 URL 为 :
足足 200 多页,实在没有耐心读完。
好在, RichEdit 还可以将内容 StreamOut 为 RTF 文档。可以以该文档为 Base ,生成 StreamIn 的字符串。
RichEdit 会循环调用下面的函数(该函数返回生成的 RTF 文档字符串),直到所有的数据读取完毕。但是, cb 每次只有 4K 。
DWORD EditStreamCallback( DWORD_PTR dwCookie,
LPBYTE pbBuff,
LONG cb,
LONG *pcb
);
效果:速度有很大提高,但是仍然是不可接受的。毕竟 foreach tlv 版本是一点一点的追加文本的,而 Stream 则是一大块一大块追加文本的。
备注:通过该函数只能全体替换 RichEdit 的内容,但是如果通过发送 Message 的话,还可以只替换选中的部分。具体可以参考 EM_STREAMIN 消息。
可能是因为即使是通过 Stream 来读取数据,但是 RichEdit 还是需要解析 RTF 文档并显示。这需要一定的时间。
四, 把 TLV 作为整体追加到 RichEdit 中
既然一段一段数据的向 RichEdit 控件中添加比较耗时。那么是否可以首先合成字符串,然后将字符串整体添加到控件中呢。
第一种方法,
void StrPlus( char * pucData , int unDataLen )
{
CString strResult ;
CString str ;