今天一位同事要離開公司到電腦報(bào)去做事,中午大家為他舉行了一個(gè)歡送會(huì),大家都喝得挺多。 送走那位同事之后,我回到了辦公室,覺得頭有點(diǎn)暈,不想做事,于是就把集聚在心中,這幾天對(duì)MFC框架中的CRichEditCtrl的不滿,發(fā)泄在這篇blog上,希望前輩們能夠多指教,也希望能夠?yàn)楹髞碚邟叱恍㎝FC開發(fā)歷程中的障礙。 - 不能夠自動(dòng)初始化
- 不能夠接受TAB鍵
- 不能夠通過屬性設(shè)置自動(dòng)換行
- 不能顯示圖片等其他OLE對(duì)象
- 不能夠使用Ctrl+C來實(shí)現(xiàn)拷貝
不能夠自動(dòng)初始化 當(dāng)我第一次將Rich Edit控件放在資源窗體上的時(shí)候,發(fā)現(xiàn)程序根本就不能運(yùn)行。后來才找到原因,原來Rich Edit 控件是Ole類型的控件。在加載Rich Edit 控件的時(shí)候,必須進(jìn)行初始化。代碼如下: BOOLCTestApp::InitInstance(){ ..... AfxInitRichEdit(); } 不能夠接受TAB鍵 將 RichEdit控件放到資源窗體上的時(shí)候,發(fā)現(xiàn)它的屬性頁中并沒有設(shè)置接受TAB鍵的設(shè)置,導(dǎo)致當(dāng)把焦點(diǎn)放到Rich Edit 控件上的時(shí)候,一按tab鍵,焦點(diǎn)就移動(dòng)到下一個(gè)控件上面去了。 具體解決方法就是重載Rich Edit控件的OnGetDlgCode: 例子代碼: .h文件: class CMyRichEdit : public CRichEditCtrl{
........ afx_msg UINT OnGetDlgCode( ); ........
} .cpp文件: BEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl) ON_WM_GETDLGCODE( ) END_MESSAGE_MAP()
UINT COleRichEditCtrl::OnGetDlgCode( ){ return DLGC_WANTTAB; }
不能夠通過屬性設(shè)置自動(dòng)換行 當(dāng)把Rich Edit控件放到資源窗體上的時(shí)候,發(fā)現(xiàn)在它的屬性窗體中并沒有設(shè)置Rich Edit控件自動(dòng)換行的屬性設(shè)置。要達(dá)到這一目的,例子代碼如下: BOOL CTestDlg::InitDialog(){ ............. //m_RichEdit為窗體類的成員變量 this->m_RichEdit.SetTargetDevice(NULL,0); ............ }
不能顯示圖片等其他OLE對(duì)象 MFC提供的CRichEditCtrl沒有提供直接顯示圖片等OLE對(duì)象的屬性或方法設(shè)置,但是提供了一個(gè)接口SetOLECallback( IRichEditOleCallback* pCallback ); 要讓CRichEditCtrl顯示圖片,就得在IRichEditOleCallback上下功夫。 IRichEditOleCallback是Windows中的接口,它的定義如下: ContextSensitiveHelp: 通過該方法通知應(yīng)用程序它將以上下文關(guān)聯(lián)方式調(diào)度幫助。 DeleteObject: 通過該方法發(fā)出通知:一個(gè)對(duì)象即將從RichEdit控件中刪除 GetCliPBoardData: 通過該方法允許RichEdit的客戶端(調(diào)用程序)提供自己的粘貼對(duì)象 GetContextMenu: 通過該方法向應(yīng)用程序提出通過鼠標(biāo)右鍵事件來獲取上下文菜單的請(qǐng)求 GetDragDropEffect: 通過該方法允許RichEdit的客戶端(調(diào)用程序)設(shè)置拖動(dòng)操作的效果 GetInPlaceContext: 通過該方法提供了應(yīng)用程序級(jí)和文檔級(jí)接口,以及必要的支持In-place激活的信息 GetNewStrorage: 通過該方法存儲(chǔ)從粘貼板或超文本流(RTF)中讀取的新對(duì)象 QueryAcceptData: 通過該方法決定在粘貼操作或拖放操作中引入的數(shù)據(jù)是否可以被接受。 QueryInsertObject: 通過該方法向應(yīng)用程序詢問某個(gè)對(duì)象是否可以被插入 ShowContainerUI: 通過該方法告知應(yīng)用程序是否顯示自己的操作界面
大致了解了IRichEditOleCallback接口后,就應(yīng)該清楚,要顯示圖片等ole對(duì)象,至少應(yīng)該實(shí)現(xiàn)GetNewStorage方法,因?yàn)樵摲椒ㄊ谴鎯?chǔ)ole對(duì)象的接口方法。
以下是接口聲明的代碼: interface IExRichEditOleCallback : IRichEditOleCallback { public: IExRichEditOleCallback(); virtual ~IExRichEditOleCallback(); int m_iNumStorages; IStorage* pStorage; DWORD m_dwRef; virtual HRESULT STDMETHODCALLTYPE GetNewStorage(LPSTORAGE* lplpstg); virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); virtual HRESULT STDMETHODCALLTYPE GetInPlaceContext(LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo); virtual HRESULT STDMETHODCALLTYPE ShowContainerUI(BOOL fShow); virtual HRESULT STDMETHODCALLTYPE QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp); virtual HRESULT STDMETHODCALLTYPE DeleteObject(LPOLEOBJECT lpoleobj); virtual HRESULT STDMETHODCALLTYPE QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict); virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); virtual HRESULT STDMETHODCALLTYPE GetClipboardData(CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj); virtual HRESULT STDMETHODCALLTYPE GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect); virtual HRESULT STDMETHODCALLTYPE GetContextMenu(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu); } 關(guān)于接口的實(shí)現(xiàn),將被附在最后的附錄中。 不能夠使用Ctrl+C來實(shí)現(xiàn)拷貝 實(shí)際上,CRichEditCtrl本身是支持Ctrl+C實(shí)現(xiàn)拷貝功能的,但是當(dāng)我在CRichiEditCtrl的繼承類中使用了IRichiEditCallback接口后,它就不在支持Ctrl+C實(shí)現(xiàn)拷貝功能了。我想問題就出在IRichEditCallback接口上。 仔細(xì)看了一遍它的幫助文檔,我發(fā)現(xiàn)問題就出在GetClipboardData上,我沒有在它的實(shí)現(xiàn)方法中寫代碼,只是返回了S_OK,如果要處理Ctrl+C,就必須返回E_NOTIMPL。
以上是我近幾天的開發(fā)經(jīng)歷,與大家分享,還希望路過的高手多多指教。 在以下關(guān)于RichEdit的代碼例子中,我參考了Mike O‘Neill 的代碼,再次謝謝他的貢獻(xiàn)。
附錄 .h文件 #if !defined(AFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_) #define AFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // OleRichEditCtrl.h : header file // #include <richole.h> ///////////////////////////////////////////////////////////////////////////// // COleRichEditCtrl window class COleRichEditCtrl : public CRichEditCtrl { // Construction public: COleRichEditCtrl(); virtual ~COleRichEditCtrl(); long StreamInFromResource(int iRes, LPCTSTR sType); protected: static DWORD CALLBACK readFunction(DWORD dwCookie, LPBYTE lpBuf, // the buffer to fill LONG nCount, // number of bytes to read LONG* nRead); // number of bytes actually read interface IExRichEditOleCallback; // forward declaration (see below in this header file) IExRichEditOleCallback* m_pIRichEditOleCallback; BOOL m_bCallbackSet; interface IExRichEditOleCallback : public IRichEditOleCallback { public: IExRichEditOleCallback(); virtual ~IExRichEditOleCallback(); int m_iNumStorages; IStorage* pStorage; DWORD m_dwRef; virtual HRESULT STDMETHODCALLTYPE GetNewStorage(LPSTORAGE* lplpstg); virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); virtual HRESULT STDMETHODCALLTYPE GetInPlaceContext(LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo); virtual HRESULT STDMETHODCALLTYPE ShowContainerUI(BOOL fShow); virtual HRESULT STDMETHODCALLTYPE QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp); virtual HRESULT STDMETHODCALLTYPE DeleteObject(LPOLEOBJECT lpoleobj); virtual HRESULT STDMETHODCALLTYPE QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict); virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); virtual HRESULT STDMETHODCALLTYPE GetClipboardData(CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj); virtual HRESULT STDMETHODCALLTYPE GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect); virtual HRESULT STDMETHODCALLTYPE GetContextMenu(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu); }; public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(COleRichEditCtrl) protected: virtual void PreSubclassWindow(); //}}AFX_VIRTUAL // Implementation public: // Generated message map functions protected: //{{AFX_MSG(COleRichEditCtrl) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //}}AFX_MSG afx_msg UINT OnGetDlgCode( ); DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_)
.cpp文件 // OleRichEditCtrl.cpp : implementation file // #include "stdafx.h" #include "OleRichEditCtrl.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // COleRichEditCtrl COleRichEditCtrl::COleRichEditCtrl() { m_bCallbackSet = FALSE; } COleRichEditCtrl::~COleRichEditCtrl() { // IExRichEditOleCallback class is a reference-counted class // which deletes itself and for which delete should not be called // delete m_pIRichEditOleCallback; } BEGIN_MESSAGE_MAP(COleRichEditCtrl, CRichEditCtrl) //{{AFX_MSG_MAP(COleRichEditCtrl) ON_WM_CREATE() //}}AFX_MSG_MAP ON_WM_GETDLGCODE( ) END_MESSAGE_MAP() // int COleRichEditCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CRichEditCtrl::OnCreate(lpCreateStruct) == -1) return -1; // m_pIRichEditOleCallback should have been created in PreSubclassWindow ASSERT( m_pIRichEditOleCallback != NULL ); // set the IExRichEditOleCallback pointer if it wasn‘t set // successfully in PreSubclassWindow if ( !m_bCallbackSet ) { SetOLECallback( m_pIRichEditOleCallback ); } return 0; } void COleRichEditCtrl::PreSubclassWindow() { // base class first CRichEditCtrl::PreSubclassWindow(); m_pIRichEditOleCallback = NULL; m_pIRichEditOleCallback = new IExRichEditOleCallback; ASSERT( m_pIRichEditOleCallback != NULL ); m_bCallbackSet = SetOLECallback( m_pIRichEditOleCallback ); } long COleRichEditCtrl::StreamInFromResource(int iRes, LPCTSTR sType) { HINSTANCE hInst = AfxGetInstanceHandle(); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(iRes), sType); DWORD len = SizeofResource(hInst, hRsrc); BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc); ASSERT(lpRsrc); CMemFile mfile; mfile.Attach(lpRsrc, len); EDITSTREAM es; es.pfnCallback = readFunction; es.dwError = 0; es.dwCookie = (DWORD) &mfile; return StreamIn( SF_RTF, es ); } /* static */ DWORD CALLBACK COleRichEditCtrl::readFunction(DWORD dwCookie, LPBYTE lpBuf, // the buffer to fill LONG nCount, // number of bytes to read LONG* nRead) // number of bytes actually read { CFile* fp = (CFile *)dwCookie; *nRead = fp->Read(lpBuf,nCount); return 0; } ///////////////////////////////////////////////////////////////////////////// COleRichEditCtrl::IExRichEditOleCallback::IExRichEditOleCallback() { pStorage = NULL; m_iNumStorages = 0; m_dwRef = 0; // set up OLE storage HRESULT hResult = ::StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE /*| STGM_DELETEONRELEASE */|STGM_CREATE , 0, &pStorage ); if ( pStorage == NULL || hResult != S_OK ) { AfxThrowOleException( hResult ); } } COleRichEditCtrl::IExRichEditOleCallback::~IExRichEditOleCallback() { } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::GetNewStorage(LPSTORAGE* lplpstg) { m_iNumStorages++; WCHAR tName[50]; swprintf(tName, L"REOLEStorage%d", m_iNumStorages); HRESULT hResult = pStorage->CreateStorage(tName, STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE , 0, 0, lplpstg ); if (hResult != S_OK ) { ::AfxThrowOleException( hResult ); } return hResult; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::QueryInterface(REFIID iid, void ** ppvObject) { HRESULT hr = S_OK; *ppvObject = NULL; if ( iid == IID_IUnknown || iid == IID_IRichEditOleCallback ) { *ppvObject = this; AddRef(); hr = NOERROR; } else { hr = E_NOINTERFACE; } return hr; } ULONG STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::AddRef() { return ++m_dwRef; } ULONG STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::Release() { if ( --m_dwRef == 0 ) { delete this; return 0; } return m_dwRef; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::ShowContainerUI(BOOL fShow) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::DeleteObject(LPOLEOBJECT lpoleobj) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::ContextSensitiveHelp(BOOL fEnterMode) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::GetClipboardData(CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return S_OK; } HRESULT STDMETHODCALLTYPE COleRichEditCtrl::IExRichEditOleCallback::GetContextMenu(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu) { return S_OK; } // TabRichEditCtrl 消息處理程序 UINT COleRichEditCtrl::OnGetDlgCode( ){ return DLGC_WANTTAB; } |