您的位置:首页 > 其它

RichEdit读取rtf格式

2017-01-23 16:02 232 查看
接到需求,需要在播放器播放失败时显示播放失败的错误原因,引导用户自己解决,减轻客服压力,在看到产品设计挺长的原因说明后,考虑维护简单,避免使用xml配置中直接写死的方式来解决,分析从以下方式来解决

1.考虑过通过云配线上请求。

这样的好处是可以较为实时的更新错误原因的内容,使用户能够较实时得获取到最新的帮助信息,但是弊端是无法保留UI中的格式信息,且实现较为繁琐,在与产品沟通后,要求保留错误原因信息的格式信息

2.考虑txt自定义一套简单的格式结构。

能够保留格式,但是实现起来太复杂,并且当有全新的格式,样式时需要不断的添加新的结点信息。并且一套下来可能只有创建此语法的人来维护了。

3.使用图片来实现

能够保留格式信息,但是图片格式较大,并且当内容较多时,实现上下滚动困难。

4.使用html加浏览器控件来实现基本具体所有的优点,但是难以接受的是需要携带浏览器控件带来的臃肿。

经过权衡,最终考虑使用RTF文件配合RichEdit来实现

RTF文件跨平台,是一个相对来说许多的文本编辑器都支持。并且这样实现后用户在安装目录也可以自己打开查看。:
也称富文本格式(Rich Text Format, 一般简称为RTF),意为多文本格式是由微软公司开发的跨平台文档格式。大多数的文字处理软件都能读取和保存RTF文档。[1] 
rtf是一种非常流行的文件结构,很多文字编辑器都支持它,vb等开发工具甚至还提供了richtxtbox的控件。 ——《百度百科》

RTF文件跨平台,是一个相对来说许多的文本编辑器都支持。并且这样实现后用户在安装目录也可以自己打开查看。
RicheEdit使用大全:
http://www.cppblog.com/wanghaiguang/archive/2013/08/21/202683.aspx

对比一下接口,输入输出主要有三种方式:
1) GetWindowText / SetWindowText(可以输入最多 64K 的正文)
2) EM_GETTEXTEX / EM_SETTEXTEX
3) StreamIn / StreamOut (主要用于RTF等格式输出)

具体的使用可以参照上面的使用大全和网上资料
Obviously,我们应该使用第三个接口,StreamIn. 先看看MFC中如何使用

static DWORD CALLBACK StreamInCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
CFile* pFile = (CFile*)dwCookie;
*pcb = pFile->Read(pbBuff, cb);
return 0;
}

void CRichEditInputRTFDlg::OnBnClickedOk()
{
CFileDialog dlg(TRUE, 0, 0, OFN_HIDEREADONLY, L"(*.rtf)|*.rtf||");
if (dlg.DoModal() != IDOK)  return;

CString sFilePath = dlg.GetPathName();
CFile cFile(sFilePath, CFile::modeRead);
EDITSTREAM es;
es.dwCookie = (DWORD)&cFile;
es.pfnCallback = StreamInCallback;
CRichEditCtrl* m_cRichEdit = (CRichEditCtrl*)GetDlgItem(IDC_RICHEDIT21);
m_cRichEdit->StreamIn(SF_RTF, es);
}

RichEdit相关的定义
typedef DWORD (CALLBACK *EDITSTREAMCALLBACK)(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);

typedef struct _editstream
{
DWORD_PTR dwCookie; 	// User value passed to callback as first parameter
DWORD	  dwError;		// Last error
EDITSTREAMCALLBACK pfnCallback;
} EDITSTREAM;

// Stream formats. Flags are all in low word, since high word
// gives possible codepage choice.
#define SF_TEXT 		0x0001
#define SF_RTF			0x0002
#define SF_RTFNOOBJS	0x0003		// Write only
#define SF_TEXTIZED 	0x0004		// Write only

#define SF_UNICODE		0x0010		// Unicode file (UCS2 little endian)
#define SF_USECODEPAGE	0x0020		// CodePage given by high word
#define SF_NCRFORNONASCII 0x40		// Output \uN for nonASCII
#define SFF_WRITEXTRAPAR  0x80			// Output \par at end


要设置 RichEdit 文本,需要给 RichEdit 简单的提供一个回调函数的地址,当一切准备好时, RichEdit 会调用回调函数,并将正文缓冲区的地址传递给它。回调函数会将要发送给 RichEdit 的数据填入缓冲区或者将缓冲区的数据读出,然后等待下一次调用直到操作完成。 范例程序是流入(设置正文)和流出(取出正文)两者的例子。

最后附一下非win32的示例:
std::wstring file = L"err_reason.rtf";
FILE* pFile = _tfopen(file.c_str(), L"rt");
EDITSTREAM es;
es.dwCookie = (DWORD_PTR)pFile;
es.pfnCallback = EditStreamCallBack;
richReason->StreamIn(SF_RTF, es);
fclose(pFile);

static DWORD CALLBACK EditStreamCallBack(
DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
FILE* pFile = (FILE*)dwCookie;
*pcb = fread((void*)pbBuff, 1, cb, pFile);
return 0;
}


需要注意的是,一个文件会分多次来读取,每次最多4096个字节。并且文件的关闭会在文件全部读取完成时调用。

这种实现适用于关于,版权声明,错误说明等大段文字的应用场景。

参考文献:http://www.ggdoc.com/cmljaHRleHRlZGl00/MzEwOGNhZTgxNzJkZWQ2MzBiMWNiNmQ20/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: