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

原创 2006年06月07日 15:59:00

今天一位同事要离开公司到电脑报去做事,中午大家为他举行了一个欢送会,大家都喝得挺多。
送走那位同事之后,我回到了办公室,觉得头有点晕,不想做事,于是就把集聚在心中,这几天对MFC框架中的CRichEditCtrl的不满,发泄在这篇blog上,希望前辈们能够多指教,也希望能够为后来者扫除一些MFC开发历程中的障碍。

  1. 不能够自动初始化
  2. 不能够接受TAB键
  3. 不能够通过属性设置自动换行
  4. 不能显示图片等其他OLE对象
  5. 不能够使用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;
}

 


android进程优先级,内存不足时杀进程顺序

概述 Android操作系统尝试尽可能长时间的保持应用的进程,但当可用内存很低时最终要移走一部分进程。怎样确定那些程序可以运行,那些要被销毁,Android让每一个进程在一个重要级的基础上运行,重要级...
  • litefish
  • litefish
  • 2015年03月29日 10:45
  • 2118

四、面向对象介绍 结构化程序设计、面向对象程序设计、面向对象设计的特征和优缺点

一、结构化程序设计 传统的程序设计方法可以归结为“程序=算法+数据结构”,将程序定义为处理数据的一系列过程。这种设计方法的着眼点是面向过程的,特点是数据与程序分离,即数据与数据处理分离。 结构化程...
  • tianttt
  • tianttt
  • 2014年12月14日 15:04
  • 1684

二叉树的非递归遍历以及层次遍历(前序、中序、后序)

先使用先序的方法建立一棵二叉树,然后分别使用递归与非递归的方法实现前序、中序、后序遍历二叉树,并使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组...
  • yusiguyuan
  • yusiguyuan
  • 2014年11月07日 21:11
  • 1627

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

数CRichEditCtrl的先天不足及进化方法 今天一位同事要离开公司到电脑报去做事,中午大家为他举行了一个欢送会,大家都喝得挺多。 送走那位同事之后,我回到了办公室,觉得头有点晕,不想...
  • scutlihang
  • scutlihang
  • 2011年11月17日 15:37
  • 260

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

述CRichEditCtrl的先天不足及进化方法  不能够自动初始化不能够接受TAB键不能够通过属性设置自动换行不能显示图片等其他OLE对象不能够使用Ctrl+C来实现拷贝 ...
  • wateryh
  • wateryh
  • 2012年02月08日 18:00
  • 309

任务分配与调度的共同进化方法_钟求喜.caj

  • 2013年12月28日 12:39
  • 167KB
  • 下载

基于情感学习Agent的交互式进化计算方法

  • 2013年09月28日 11:16
  • 1.07MB
  • 下载

基于多物种进化遗传算法的神经网络结构学习方法

  • 2008年02月22日 15:25
  • 175KB
  • 下载

基于局部进化的Hopfield神经网络的优化计算方法

  • 2008年05月05日 21:49
  • 423KB
  • 下载

OpenAI详解进化策略方法:可替代强化学习

OpenAI详解进化策略方法:可替代强化学习 2017-03-25 机器之心 选自OpenAI 作者:Andrej Karpathy等 机器之心编译 参与:吴...
  • ynsshzwxhzyx
  • ynsshzwxhzyx
  • 2017年03月26日 12:21
  • 229
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数CRichEditCtrl的先天不足及进化方法
举报原因:
原因补充:

(最多只允许输入30个字)