王朝网络
分享
 
 
 

数CRichEditCtrl的先天不足及进化方法

王朝other·作者佚名  2006-06-14
宽屏版  字体: |||超大  

今天一位同事要离开公司到电脑报去做事,中午大家为他举行了一个欢送会,大家都喝得挺多。

送走那位同事之后,我回到了办公室,觉得头有点晕,不想做事,于是就把集聚在心中,这几天对MFC框架中的CRichEditCtrl的不满,发泄在这篇blog上,希望前辈们能够多指教,也希望能够为后来者扫除一些MFC开发历程中的障碍。

不能够自动初始化

不能够接受TAB键

不能够通过属性设置自动换行

不能显示图片等其他OLE对象

不能够使用Ctrl+C来实现拷贝

不能够自动初始化

当我第一次将Rich Edit控件放在资源窗体上的时候,发现程序根本就不能运行。后来才找到原因,原来Rich Edit 控件是Ole类型的控件。在加载Rich Edit 控件的时候,必须进行初始化。代码如下:

BOOLCTestApp::InitInstance(){

.....

AfxInitRichEdit();

}

不能够接受TAB键

将 RichEdit控件放到资源窗体上的时候,发现它的属性页中并没有设置接受TAB键的设置,导致当把焦点放到Rich Edit 控件上的时候,一按tab键,焦点就移动到下一个控件上面去了。

具体解决方法就是重载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;

}

不能够通过属性设置自动换行

当把Rich Edit控件放到资源窗体上的时候,发现在它的属性窗体中并没有设置Rich Edit控件自动换行的属性设置。要达到这一目的,例子代码如下:

BOOL CTestDlg::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对象的接口方法。

以下是接口声明的代码:

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);

}

关于接口的实现,将被附在最后的附录中。

不能够使用Ctrl+C来实现拷贝

实际上,CRichEditCtrl本身是支持Ctrl+C实现拷贝功能的,但是当我在CRichiEditCtrl的继承类中使用了IRichiEditCallback接口后,它就不在支持Ctrl+C实现拷贝功能了。我想问题就出在IRichEditCallback接口上。

仔细看了一遍它的帮助文档,我发现问题就出在GetClipboardData上,我没有在它的实现方法中写代码,只是返回了S_OK,如果要处理Ctrl+C,就必须返回E_NOTIMPL。

以上是我近几天的开发经历,与大家分享,还希望路过的高手多多指教。

在以下关于RichEdit的代码例子中,我参考了Mike O'Neill 的代码,再次谢谢他的贡献。

附录

.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;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有