数CRichEditCtrl的先天不足及进化方法
今天一位同事要离开公司到电脑报去做事,中午大家为他举行了一个欢送会,大家都喝得挺多。
送走那位同事之后,我回到了办公室,觉得头有点晕,不想做事,于是就把集聚在心中,这几天对MFC框架中的CRichEditCtrl的不满,发泄在这篇blog上,希望前辈们能够多指教,也希望能够为后来者扫除一些MFC开发历程中的障碍。 软件开发网
不能够自动初始化
当我第一次将RichEdit控件放在资源窗体上的时候,发现程序根本就不能运行。后来才找到原因,原来RichEdit控件是Ole类型的控件。在加载RichEdit控件的时候,必须进行初始化。代码如下:
BOOLCTestApp::InitInstance(){
.....
AfxInitRichEdit(); 软件开发网
}
不能够接受TAB键
将RichEdit控件放到资源窗体上的时候,发现它的属性页中并没有设置接受TAB键的设置,导致当把焦点放到RichEdit控件上的时候,一按tab键,焦点就移动到下一个控件上面去了。
具体解决方法就是重载RichEdit控件的OnGetDlgCode:
例子代码:
.h文件:
classCMyRichEdit:publicCRichEditCtrl{
........
afx_msgUINTOnGetDlgCode();
........
}
.cpp文件:
BEGIN_MESSAGE_MAP(CMyRichEdit,CRichEditCtrl)
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
UINTCOleRichEditCtrl::OnGetDlgCode(){
returnDLGC_WANTTAB; 软件开发网
}
http://www.mscto.com
不能够通过属性设置自动换行
当把RichEdit控件放到资源窗体上的时候,发现在它的属性窗体中并没有设置RichEdit控件自动换行的属性设置。要达到这一目的,例子代码如下:
BOOLCTestDlg::InitDialog(){
.............
//m_RichEdit为窗体类的成员变量
this->m_RichEdit.SetTargetDevice(NULL,0);
............
}
不能显示图片等其他OLE对象
MFC提供的CRichEditCtrl没有提供直接显示图片等OLE对象的属性或方法设置,但是提供了一个接口SetOLECallback(IRichEditOleCallback*pCallback);
要让CRichEditCtrl显示图片,就得在IRichEditOleCallback上下功夫。
IRichEditOleCallback是Windows中的接口,它的定义如下:
ContextSensitiveHelp:
通过该方法通知应用程序它将以上下文关联方式调度帮助。
DeleteObject:
通过该方法发出通知:一个对象即将从RichEdit控件中删除
GetCliPBoardData:
通过该方法允许RichEdit的客户端(调用程序)提供自己的粘贴对象
GetContextMenu:
通过该方法向应用程序提出通过鼠标右键事件来获取上下文菜单的请求
GetDragDropEffect:
通过该方法允许RichEdit的客户端(调用程序)设置拖动操作的效果
GetInPlaceContext:
通过该方法提供了应用程序级和文档级接口,以及必要的支持In-place激活的信息
GetNewStrorage:
通过该方法存储从粘贴板或超文本流(RTF)中读取的新对象
QueryAcceptData:
通过该方法决定在粘贴操作或拖放操作中引入的数据是否可以被接受。
QueryInsertObject:
通过该方法向应用程序询问某个对象是否可以被插入
ShowContainerUI:
通过该方法告知应用程序是否显示自己的操作界面
大致了解了IRichEditOleCallback接口后,就应该清楚,要显示图片等ole对象,至少应该实现GetNewStorage方法,因为该方法是存储ole对象的接口方法。
以下是接口声明的代码:
interfaceIExRichEditOleCallback:IRichEditOleCallback
{
public:
IExRichEditOleCallback();
virtual~IExRichEditOleCallback();
intm_iNumStorages;
IStorage*pStorage;
DWORDm_dwRef;
virtualHRESULTSTDMETHODCALLTYPEGetNewStorage(LPSTORAGE*lplpstg);
virtualHRESULTSTDMETHODCALLTYPEQueryInterface(REFIIDiid,void**ppvObject);
virtualULONGSTDMETHODCALLTYPEAddRef();
virtualULONGSTDMETHODCALLTYPERelease();
virtualHRESULTSTDMETHODCALLTYPEGetInPlaceContext(LPOLEINPLACEFRAMEFAR*lplpFrame,
LPOLEINPLACEUIWINDOWFAR*lplpDoc,LPOLEINPLACEFRAMEINFOlpFrameInfo);
virtualHRESULTSTDMETHODCALLTYPEShowContainerUI(BOOLfShow);
virtualHRESULTSTDMETHODCALLTYPEQueryInsertObject(LPCLSIDlpclsid,LPSTORAGElpstg,LONGcp);
virtualHRESULTSTDMETHODCALLTYPEDeleteObject(LPOLEOBJECTlpoleobj);
virtualHRESULTSTDMETHODCALLTYPEQueryAcceptData(LPDATAOBJECTlpdataobj,CLIPFORMATFAR*lpcfFormat, DWORDreco,BOOLfReally,HGLOBALhMetaPict);
virtualHRESULTSTDMETHODCALLTYPEContextSensitiveHelp(BOOLfEnterMode);
virtualHRESULTSTDMETHODCALLTYPEGetClipboardData(CHARRANGEFAR*lpchrg,DWORDreco,LPDATAOBJECTFAR*lplpdataobj);
virtualHRESULTSTDMETHODCALLTYPEGetDragDropEffect(BOOLfDrag,DWORDgrfKeyState,LPDWORDpdwEffect);
virtualHRESULTSTDMETHODCALLTYPEGetContextMenu(WORDseltyp,LPOLEOBJECTlpoleobj,CHARRANGEFAR*lpchrg, HMENUFAR*lphmenu);
}
关于接口的实现,将被附在最后的附录中。
不能够使用Ctrl C来实现拷贝
实际上,CRichEditCtrl本身是支持Ctrl C实现拷贝功能的,但是当我在CRichiEditCtrl的继承类中使用了IRichiEditCallback接口后,它就不在支持Ctrl C实现拷贝功能了。我想问题就出在IRichEditCallback接口上。
仔细看了一遍它的帮助文档,我发现问题就出在GetClipboardData上,我没有在它的实现方法中写代码,只是返回了S_OK,如果要处理Ctrl C,就必须返回E_NOTIMPL。
以上是我近几天的开发经历,与大家分享,还希望路过的高手多多指教。
在以下关于RichEdit的代码例子中,我参考了MikeO'Neill的代码,再次谢谢他的贡献。
附录
.h文件
#if!defined(AFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_)
#defineAFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_ http://www.mscto.com
#if_MSC_VER>1000
#pragmaonce
#endif//_MSC_VER>1000
//OleRichEditCtrl.h:headerfile
//
#include<richole.h>
/
//COleRichEditCtrlwindow
classCOleRichEditCtrl:publicCRichEditCtrl
{
//Construction
public:
COleRichEditCtrl();
virtual~COleRichEditCtrl();
longStreamInFromResource(intiRes,LPCTSTRsType);
protected:
staticDWORDCALLBACKreadFunction(DWORDdwCookie,
LPBYTElpBuf, //thebuffertofill
LONGnCount, //numberofbytestoread
LONG*nRead); //numberofbytesactuallyread
interfaceIExRichEditOleCallback; //forwarddeclaration(seebelowinthisheaderfile)
IExRichEditOleCallback*m_pIRichEditOleCallback;
BOOLm_bCallbackSet;
interfaceIExRichEditOleCallback:publicIRichEditOleCallback
{
public:
IExRichEditOleCallback();
virtual~IExRichEditOleCallback();
intm_iNumStorages;
IStorage*pStorage;
DWORDm_dwRef;
virtualHRESULTSTDMETHODCALLTYPEGetNewStorage(LPSTORAGE*lplpstg);
virtualHRESULTSTDMETHODCALLTYPEQueryInterface(REFIIDiid,void**ppvObject);
virtualULONGSTDMETHODCALLTYPEAddRef();
virtualULONGSTDMETHODCALLTYPERelease();
virtualHRESULTSTDMETHODCALLTYPEGetInPlaceContext(LPOLEINPLACEFRAMEFAR*lplpFrame,
LPOLEINPLACEUIWINDOWFAR*lplpDoc,LPOLEINPLACEFRAMEINFOlpFrameInfo);
virtualHRESULTSTDMETHODCALLTYPEShowContainerUI(BOOLfShow);
virtualHRESULTSTDMETHODCALLTYPEQueryInsertObject(LPCLSIDlpclsid,LPSTORAGElpstg,LONGcp);
virtualHRESULTSTDMETHODCALLTYPEDeleteObject(LPOLEOBJECTlpoleobj);
virtualHRESULTSTDMETHODCALLTYPEQueryAcceptData(LPDATAOBJECTlpdataobj,CLIPFORMATFAR*lpcfFormat,
DWORDreco,BOOLfReally,HGLOBALhMetaPict);
virtualHRESULTSTDMETHODCALLTYPEContextSensitiveHelp(BOOLfEnterMode);
virtualHRESULTSTDMETHODCALLTYPEGetClipboardData(CHARRANGEFAR*lpchrg,DWORDreco,LPDATAOBJECTFAR*lplpdataobj);
virtualHRESULTSTDMETHODCALLTYPEGetDragDropEffect(BOOLfDrag,DWORDgrfKeyState,LPDWORDpdwEffect);
virtualHRESULTSTDMETHODCALLTYPEGetContextMenu(WORDseltyp,LPOLEOBJECTlpoleobj,CHARRANGEFAR*lpchrg,
HMENUFAR*lphmenu);
};
public:
//Overrides
//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(COleRichEditCtrl)
protected:
virtualvoidPreSubclassWindow();
//}}AFX_VIRTUAL
//Implementation
public:
软件开发网
//Generatedmessagemapfunctions
protected:
//{{AFX_MSG(COleRichEditCtrl)
afx_msgintOnCreate(LPCREATESTRUCTlpCreateStruct);
//}}AFX_MSG
afx_msgUINTOnGetDlgCode();
DECLARE_MESSAGE_MAP()
};
/ 软件开发网
//{{AFX_INSERT_LOCATION}}
//MicrosoftVisualC willinsertadditionaldeclarationsimmediatelybeforethepreviousline.
#endif//!defined(AFX_OLERICHEDITCTRL_H__3DFF15EE_7336_4297_9620_7F00B611DAA1__INCLUDED_)
.cpp文件
//OleRichEditCtrl.cpp:implementationfile
//
#include"stdafx.h"
#include"OleRichEditCtrl.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
/
//COleRichEditCtrl
COleRichEditCtrl::COleRichEditCtrl()
{
m_bCallbackSet=FALSE;
} http://www.mscto.com
COleRichEditCtrl::~COleRichEditCtrl()
{
//IExRichEditOleCallbackclassisareference-countedclass
//whichdeletesitselfandforwhichdeleteshouldnotbecalled
//deletem_pIRichEditOleCallback;
}
BEGIN_MESSAGE_MAP(COleRichEditCtrl,CRichEditCtrl)
//{{AFX_MSG_MAP(COleRichEditCtrl)
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
// http://www.mscto.com
intCOleRichEditCtrl::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(CRichEditCtrl::OnCreate(lpCreateStruct)==-1)
return-1;
//m_pIRichEditOleCallbackshouldhavebeencreatedinPreSubclassWindow
ASSERT(m_pIRichEditOleCallback!=NULL);
//settheIExRichEditOleCallbackpointerifitwasn'tset
//successfullyinPreSubclassWindow
if(!m_bCallbackSet)
{
SetOLECallback(m_pIRichEditOleCallback);
}
return0;
}
软件开发网
voidCOleRichEditCtrl::PreSubclassWindow()
{
//baseclassfirst
CRichEditCtrl::PreSubclassWindow();
m_pIRichEditOleCallback=NULL;
m_pIRichEditOleCallback=newIExRichEditOleCallback;
ASSERT(m_pIRichEditOleCallback!=NULL);
m_bCallbackSet=SetOLECallback(m_pIRichEditOleCallback);
}
longCOleRichEditCtrl::StreamInFromResource(intiRes,LPCTSTRsType)
{
HINSTANCEhInst=AfxGetInstanceHandle();
HRSRChRsrc=::FindResource(hInst,
MAKEINTRESOURCE(iRes),sType);
DWORDlen=SizeofResource(hInst,hRsrc);
BYTE*lpRsrc=(BYTE*)LoadResource(hInst,hRsrc);
ASSERT(lpRsrc);
CMemFilemfile;
mfile.Attach(lpRsrc,len); 软件开发网
EDITSTREAMes;
es.pfnCallback=readFunction;
es.dwError=0;
es.dwCookie=(DWORD)&mfile;
returnStreamIn(SF_RTF,es);
}
/*static*/
DWORDCALLBACKCOleRichEditCtrl::readFunction(DWORDdwCookie,
LPBYTElpBuf, //thebuffertofill
LONGnCount, //numberofbytestoread
LONG*nRead) //numberofbytesactuallyread
{
CFile*fp=(CFile*)dwCookie;
*nRead=fp->Read(lpBuf,nCount);
return0;
} http://www.mscto.com
/
COleRichEditCtrl::IExRichEditOleCallback::IExRichEditOleCallback()
{
pStorage=NULL;
m_iNumStorages=0;
m_dwRef=0;
http://www.mscto.com
//setupOLEstorage
HRESULThResult=::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()
{
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::GetNewStorage(LPSTORAGE*lplpstg)
{
m_iNumStorages ;
WCHARtName[50];
swprintf(tName,L"REOLEStorage%d",m_iNumStorages); 软件开发网
HRESULThResult=pStorage->CreateStorage(tName,
STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
0,0,lplpstg);
if(hResult!=S_OK)
{
::AfxThrowOleException(hResult);
}
returnhResult;
} http://www.mscto.com
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::QueryInterface(REFIIDiid,void**ppvObject)
{
HRESULThr=S_OK;
*ppvObject=NULL;
if(iid==IID_IUnknown||
iid==IID_IRichEditOleCallback)
{
*ppvObject=this;
AddRef();
hr=NOERROR;
}
else
{
hr=E_NOINTERFACE;
}
returnhr;
}
ULONGSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::AddRef()
{
return m_dwRef;
}
ULONGSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::Release()
{
if(--m_dwRef==0)
{
deletethis;
return0;
}
http://www.mscto.com
returnm_dwRef;
}
http://www.mscto.com
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::GetInPlaceContext(LPOLEINPLACEFRAMEFAR*lplpFrame,
LPOLEINPLACEUIWINDOWFAR*lplpDoc,LPOLEINPLACEFRAMEINFOlpFrameInfo)
{
returnS_OK;
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::ShowContainerUI(BOOLfShow)
{
returnS_OK;
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::QueryInsertObject(LPCLSIDlpclsid,LPSTORAGElpstg,LONGcp)
{
returnS_OK;
} 软件开发网
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::DeleteObject(LPOLEOBJECTlpoleobj)
{
returnS_OK;
}
http://www.mscto.com
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::QueryAcceptData(LPDATAOBJECTlpdataobj,CLIPFORMATFAR*lpcfFormat,
DWORDreco,BOOLfReally,HGLOBALhMetaPict)
{
returnS_OK;
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::ContextSensitiveHelp(BOOLfEnterMode)
{
returnS_OK;
}
http://www.mscto.com
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::GetClipboardData(CHARRANGEFAR*lpchrg,DWORDreco,LPDATAOBJECTFAR*lplpdataobj)
{
returnE_NOTIMPL;
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::GetDragDropEffect(BOOLfDrag,DWORDgrfKeyState,LPDWORDpdwEffect)
{
returnS_OK;
}
HRESULTSTDMETHODCALLTYPE
COleRichEditCtrl::IExRichEditOleCallback::GetContextMenu(WORDseltyp,LPOLEOBJECTlpoleobj,CHARRANGEFAR*lpchrg,
HMENUFAR*lphmenu)
{
returnS_OK;
}
//TabRichEditCtrl消息处理程序
UINTCOleRichEditCtrl::OnGetDlgCode(){
returnDLGC_WANTTAB;
}