中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Visual C++ > WINDOWS标准界面元素
类似 MSN 信息发送框的制作(上)
作者:未知 时间:2005-07-20 14:11 出处:VC知识库 责编:chinaitpower
              摘要:类似 MSN 信息发送框的制作(上)

类似 MSN 信息发送框的制作(上)


作者:北方工业大学 阙荣文 (querw)


下载源代码

一、引言
   用 MSN 和 QQ 等聊天的时候,当用户输入特定意义的字符串时,系统回自动用一张小图片替代.比如输入" : ) "系统
会用一个小笑脸代替。我要实现的就是这样一个信息输入框 。这个信息输入框由两部分组成:图案选择器和多功能文本框。本篇介绍多功能文本框。

二、原理简介

1、主要功能用CRichEditCtrl实现,像设置字体,设置字体颜色,字号等等CRichEditCtrl都提供了很完善的支持,我就不一一赘述了。

CRichEditCtrl 主要的不足在于以下几个方面:

  • (1).没有右键菜单
  • (2).不能插入图片(这是实现转义字符显示的关键)
  • (3).RTF格式输入输出不够方便(涉及到回调函数的递归调用)
  •    我扩展了CRichEditCtrl类CRichEditCtrlEx实现了上述功能.参考了很多网上的文章,对所有公开源码的开发人员表示崇高的敬意!!

    2、实现右键菜单:

    ///生成右键菜单

    void CRichEditCtrlEx::OnRButtonUp(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	//设置为焦点
    	SetFocus();
    	//创建一个弹出式菜单
    	CMenu popmenu;
    	popmenu.CreatePopupMenu();
    	//添加菜单项目
    	popmenu.AppendMenu(0, ID_RICH_UNDO, "&Undo");
    	popmenu.AppendMenu(0, MF_SEPARATOR);
    	popmenu.AppendMenu(0, ID_RICH_CUT, "&Cut");
    	popmenu.AppendMenu(0, ID_RICH_COPY, "C&opy");
    	popmenu.AppendMenu(0, ID_RICH_PASTE, "&Paste");
    	popmenu.AppendMenu(0, ID_RICH_CLEAR, "C&lear");
    	popmenu.AppendMenu(0, MF_SEPARATOR);
    	popmenu.AppendMenu(0, ID_RICH_SELECTALL, "Select &All");
    	popmenu.AppendMenu(0, MF_SEPARATOR);
    	popmenu.AppendMenu(0, ID_RICH_SETFONT, "Select &Font");
    	
    	//初始化菜单项
    	UINT nUndo=(CanUndo() ? 0 : MF_GRAYED );
    	popmenu.EnableMenuItem(ID_RICH_UNDO, MF_BYCOMMAND|nUndo);
    	
    	UINT nSel=((GetSelectionType()!=SEL_EMPTY) ? 0 : MF_GRAYED) ;
    	popmenu.EnableMenuItem(ID_RICH_CUT, MF_BYCOMMAND|nSel);
    	popmenu.EnableMenuItem(ID_RICH_COPY, MF_BYCOMMAND|nSel);
    	popmenu.EnableMenuItem(ID_RICH_CLEAR, MF_BYCOMMAND|nSel);
    	
    	UINT nPaste=(CanPaste() ? 0 : MF_GRAYED) ;
    	popmenu.EnableMenuItem(ID_RICH_PASTE, MF_BYCOMMAND|nPaste);
    	
    	//显示菜单
    	CPoint pt;
    	GetCursorPos(&pt);
    	popmenu.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
    	popmenu.DestroyMenu();
    	CRichEditCtrl::OnRButtonDown(nFlags, point);
    	CRichEditCtrl::OnRButtonUp(nFlags, point);
    }
    3、关于如何把图片插入到RichEdit中,国外由很多文章介绍,都是(我看到的都是)通过插入OLE对象来实现.主要用两个函数,还涉及到了和多接口的调用。

    (1)从文件创建OLE对象OleCreateFromFile();
    void CRichEditCtrlEx::InsertBitmap(CString szFileName)
    {
    	USES_CONVERSION;
    	SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &m_lpLockBytes);
    	if (sc != S_OK)
    		AfxThrowOleException(sc);
    	ASSERT(m_lpLockBytes != NULL);
    	
    	sc = ::StgCreateDocfileOnILockBytes(m_lpLockBytes,
    		STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
    	if (sc != S_OK)
    	{
    		VERIFY(m_lpLockBytes->Release() == 0);
    		m_lpLockBytes = NULL;
    		AfxThrowOleException(sc);
    	}
    	
    	// attempt to create the object
    	sc = ::OleCreateFromFile(CLSID_NULL, T2COLE(szFileName),
            IID_IUnknown, OLERENDER_DRAW, NULL, NULL, 
            m_lpStorage, (void **)&m_lpObject);
    	if ( sc != S_OK )
    	{
    		TCHAR * lpMsgBuf;
    		::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    			FORMAT_MESSAGE_FROM_SYSTEM, NULL, 
    			::GetLastError(),
    			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    			(LPTSTR) &lpMsgBuf, 0, NULL );
    		CString msg( lpMsgBuf );
    		msg += _T("\n\n\nThe following file, created in\n"
    			"Simulation->Plot, may be missing due\n"
    			"to not doing a File->Save Workspace:\n\n" );
    		msg += szFileName;
    		AfxMessageBox( msg, MB_OK );
    		::LocalFree( lpMsgBuf );
    		return;
    	}
    	
    	// m_lpObject is currently an IUnknown, convert to IOleObject
    	if (m_lpObject != NULL)
    	{
    		LPUNKNOWN lpUnk = m_lpObject;
    		m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
    		lpUnk->Release();
    		if (m_lpObject == NULL)
    			AfxThrowOleException(E_OUTOFMEMORY);
    	}
    	
    	// cache the IViewObject interface
    	m_lpViewObject = QUERYINTERFACE(m_lpObject, IViewObject2);
    	if (m_lpViewObject == NULL)
    		return;
    	
    	// setup for advises; we assume that OLE cleans them up properly
    	LPADVISESINK lpAdviseSink =
    		(LPADVISESINK)GetInterface(&IID_IAdviseSink);
    	
    	// set up view advise
    	VERIFY(m_lpViewObject->SetAdvise(DVASPECT_CONTENT, 0, lpAdviseSink)
    		== S_OK);
    	
    	// the server shows these in its user-interface
    	//  (as document title and in File Exit menu)
    	m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
    		T2COLE(_T("Test")));
    	
    	// all items are "contained" -- this makes our reference to this object
    	//  weak -- which is needed for links to embedding silent update.
    	OleSetContainedObject(m_lpObject, TRUE);
    	
    	CHARRANGE cr;
    	this->GetSel( cr );
    	cr.cpMin = cr.cpMax -1;
    	this->SetSel( cr );
    	
    	REOBJECT reo;
    	memset( &reo, 0, sizeof( reo ) );
    	reo.cbStruct = sizeof( reo );
    	CLSID classID;
    	if ( m_lpObject->GetUserClassID( &classID ) != S_OK)
    		classID = CLSID_NULL;
    	reo.clsid = classID;
    	reo.cp = REO_CP_SELECTION;
    	reo.poleobj = m_lpObject;
    	reo.pstg = m_lpStorage;
    	LPOLECLIENTSITE lpClientSite;
    	this->GetIRichEditOle()->GetClientSite( &lpClientSite );
    	reo.polesite = lpClientSite;
    	SIZEL sizel;
    	sizel.cx = sizel.cy = 0; // let richedit determine initial size
    	reo.sizel = sizel;
    	reo.dvaspect = DVASPECT_CONTENT;
    	reo.dwFlags = REO_RESIZABLE;
    	reo.dwUser = 0;
    	HRESULT hr = this->GetIRichEditOle()->InsertObject( &reo );
    	
    }
    
    (2)根据位图句柄创建OleCreateStaticFromData();用这个函数可以把资源中的图片插入到文本框中
    void CRichEditCtrlEx::InsertBitmap(HBITMAP hBitmap)
    {
    	STGMEDIUM stgm;
    	stgm.tymed = TYMED_GDI;    // Storage medium = HBITMAP handle
    	stgm.hBitmap = hBitmap;
    	stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium
    	
    	FORMATETC fm;
    	fm.cfFormat = CF_BITMAP;    // Clipboard format = CF_BITMAP
    	fm.ptd = NULL;       // Target Device = Screen
    	fm.dwAspect = DVASPECT_CONTENT;   // Level of detail = Full content
    	fm.lindex = -1;       // Index = Not applicaple
    	fm.tymed = TYMED_GDI;  
    	
    	////创建输入数据源
    	IStorage *pStorage; 
    	
    	///分配内存
    	LPLOCKBYTES lpLockBytes = NULL;
    	SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
    	if (sc != S_OK)
    		AfxThrowOleException(sc);
    	ASSERT(lpLockBytes != NULL);
    	
    	sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
    		STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
    	if (sc != S_OK)
    	{
    		VERIFY(lpLockBytes->Release() == 0);
    		lpLockBytes = NULL;
    		AfxThrowOleException(sc);
    	}
    	ASSERT(pStorage != NULL);
    	
    	COleDataSource *pDataSource = new COleDataSource;
    	pDataSource->CacheData(CF_BITMAP, &stgm);
    	LPDATAOBJECT lpDataObject = 
    		(LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
    	
    	///获取RichEdit的OLEClientSite
    	LPOLECLIENTSITE lpClientSite;
    	this->GetIRichEditOle()->GetClientSite( &lpClientSite );
    	
    	
    	///创建OLE对象
    	IOleObject *pOleObject;
    	sc = OleCreateStaticFromData(lpDataObject,IID_IOleObject,OLERENDER_FORMAT,
    		&fm,lpClientSite,pStorage,(void **)&pOleObject);
    	if(sc!=S_OK)
    		AfxThrowOleException(sc);
    	
    	///插入OLE对象
    	
    	REOBJECT reobject;
    	ZeroMemory(&reobject, sizeof(REOBJECT));
    	reobject.cbStruct = sizeof(REOBJECT);
    	
    	CLSID clsid;
    	sc = pOleObject->GetUserClassID(&clsid);
    	if (sc != S_OK)
    		AfxThrowOleException(sc);
    	
    	reobject.clsid = clsid;
    	reobject.cp = REO_CP_SELECTION;
    	reobject.dvaspect = DVASPECT_CONTENT;
    	reobject.poleobj = pOleObject;
    	reobject.polesite = lpClientSite;
    	reobject.pstg = pStorage;
    	
    	HRESULT hr = this->GetIRichEditOle()->InsertObject( &reobject );
    	
    }
    
    4、读取/写入RTF格式字符串
      CRichEditCtrl 提供了两个函数StreamIn()和StreamOut()来实现这个功能,输出的内容包含文本信息和字体信息。我把这两个函数重新包装了一下 ,用GetRTF()把格式文本返回到一个CString变量中SetRTF(CString )实现逆过程。具体代码参看本文附带的工程文件。

    三、到此,这个多功能文本框就已经基本能满足我的要求了。但是如何选择表情符号? 如何自动替换? 还是个问题。(待续)
    关闭本页
     
    首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
    Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有