如何为 WTL CRichEditCtrl 类添加序列化支持






4.08/5 (5投票s)
一个小型类,
引言
WTL 包含许多控件类,提供标准的界面元素。其中之一是 CRichEditCtrl
- 一个富文本编辑控件,它理解一些基本的 RTF 格式,并允许使用多种字体、颜色等。但是,WTL 实现中缺少 MFC 对应版本的一些有用功能,其中之一就是无法序列化 CRichEditCtrl
。
因此,我编写了一个小类 CRichEditEx
,为 CRichEditCtrl
类添加了序列化支持。该类使用 CXArchive 类 [^],该类也是由我开发的,基本上是 MFC 代码的移植。
CRichEditEx
template <class T> class CRichEditEx : public CWindowImpl<T, CRichEditCtrl> { private: bool m_bRTF; // when true, indicates // that CRichEditCtrl should store paragraph // and character-formatting characteristics. /************************************************************ * Function......: Stream * Parameters....: Ar - archive class * bSelection - indicates whether only selected text should * be saved or read * Returns.......: None * Description...: Transfers data into or out of a rich edit control ************************************************************/ void Stream(CXArchive& Ar, bool bSelection) { ATLASSERT(::IsWindow(m_hWnd)); int nFormat; // indicates whether stream I/O should include formatting EDITSTREAM es = {0, 0, EditStreamCallBack}; es.dwCookie = (DWORD)&Ar; if (m_bRTF) // rich edit control maintains formatting information nFormat = SF_RTF; else // rich edit control does not maintain formatting information nFormat = SF_TEXT; if (bSelection) nFormat |= SFF_SELECTION; if (Ar.IsStoring()) // Store text from the rich edit control into an output stream StreamOut(nFormat, es); else { // Insert text from an input stream into the rich edit control StreamIn(nFormat, es); Invalidate(); } } /****************************************************************** * Function......: EditStreamCallBack * Parameters....: dwCookie - application-defined value * pbBuff - data buffer * cb - number of bytes to read or write * pcb - number of bytes transferred * Returns.......: Returns 0 if no error, otherwise return error code * Description...: Application defined callback function * used to transfer a stream of data into or out of a rich edit control ******************************************************************/ static DWORD CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) { ATLASSERT(dwCookie != 0); ATLASSERT(pcb != NULL); DWORD dwRet = 0; // Retrieve an archive object CXArchive * pAr = (CXArchive*)dwCookie; pAr->Flush(); *pcb = cb; try { if (pAr->IsStoring()) // Save text pAr->GetFile()->Write(pbBuff, cb); else // Load test *pcb = pAr->GetFile()->Read(pbBuff, cb); } catch(CXException& e) { *pcb = 0; dwRet = e.GetErrorNumber(); } return dwRet; } public: DECLARE_WND_SUPERCLASS(NULL, CRichEditCtrl::GetWndClassName()) /****************************************************************** * Function......: Constructor * Parameters....: None * Returns.......: None * Description...: Initializes a class object *******************************************************************/ CRichEditEx() { m_bRTF = true; } BOOL PreTranslateMessage(MSG* pMsg) { pMsg; return FALSE; } BEGIN_MSG_MAP(CRichEditEx) END_MSG_MAP() /***************************************************************** * Function......: SetStreamFormat * Parameters....: Formatting flag value * Returns.......: None * Description...: Sets a formatting flag ****************************************************************/ void SetStreamFormat(bool bRTF) { m_bRTF = bRTF; } /***************************************************************** * Function......: GetStreamFormat * Parameters....: None * Returns.......: Formatting flag * Description...: Gets a formatting flag ***************************************************************/ bool GetStreamFormat() { return m_bRTF; } /**************************************************************** * Function......: Serialize * Parameters....: Ar - archive class * Returns.......: None * Description...: Reads/writes CRichEditCtrl object from/to archive ****************************************************************/ void Serialize(CXArchive& Ar) { ATLASSERT(::IsWindow(m_hWnd)); Stream(Ar, false); } };
使用代码
1. 像这样从 CRichEditEx
派生您的类
class CRichEditDemoView : public CRichEditEx<CRichEditDemoView> { ... };2. 将
CXFile
和 CXArchive
类添加到您的项目中#include "File.h" #include "Archive.h"3. 在您想要保存富文本编辑控件内容的任何代码位置,添加以下代码
LRESULT OnFileSave(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { string strFile = "demo.txt"; try { CXFile file; file.Open(strFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CXArchive ar(&file, CXArchive::store); m_view.Serialize(ar); ar.Close(); } catch (CXException& Ex) { MessageBox(Ex.GetErrorDesc().c_str(), _T("Richedit Demo"), MB_OK); } catch (...) { MessageBox(_T("Unexpected error"), _T("Richedit Demo"), MB_OK); } return 0; }4. 在您想要从文件中加载富文本编辑控件内容的任何代码位置,添加以下代码
LRESULT OnFileOpen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { string strFile = "demo.txt"; try { CXFile file; file.Open(strFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); CXArchive ar(&file, CXArchive::load); m_view.Serialize(ar); ar.Close(); } catch (CXException& Ex) { MessageBox(Ex.GetErrorDesc().c_str(), _T("Richedit Demo"), MB_OK); } catch (...) { MessageBox(_T("Unexpected error"), _T("Richedit Demo"), MB_OK); } return 0; }
演示项目
演示项目包含 CRichEditEx
、CXArchive
、CXFile
类的实现以及如何使用它们的示例。
选择“文件”->“保存”会将富文本编辑控件的内容存储到文件中,“文件”->“打开”会将文本插入到富文本编辑控件中。
历史
- 2004 年 10 月 12 日 - 初始发布。
- 2004 年 10 月 13 日 - 修复了一个错误,即从
CRichEditEx
派生的类的成员方法无法被CWindowImpl
调用。感谢 Stuart Dootson 指出这一点。
免责声明
本软件及其附带的文件按“原样”分发,不提供任何形式的保证,无论是明示的还是暗示的。对于可能造成的任何损害,概不负责。用户必须承担使用本软件的全部风险。