FaceEdit.cpp
上传用户:dgvc2008
上传日期:2021-01-21
资源大小:65k
文件大小:11k
- /*--------------------------------------
- * Copyright (c) 2004
- * All rights reserved.
- * download by http://www.codefans.net
- * 文件名称: FaceEdit.cpp
- * 摘 要: 类 CFaceEdit 实现部分
- *
- * 当前版本: 1.01 VC7版
- * 作 者: Flanker(刘翔)
- * 完成日期: 2004年10月26日
- * 修改日期: 2004年11月12日
- --------------------------------------*/
- #include "StdAfx.h"
- #include ".faceedit.h"
- #include <string>
- #include <vector>
- #include <algorithm>
- using namespace std;
- #include <Richole.h>
- #include <afxodlgs.h>
- #include <atlconv.h> //A2W,在VC6下面要包含。
- //全局函数
- bool less_than(stFace &face1, stFace &face2); //声明排序的"条件"函数
- void InsertBitmap(CRichEditCtrl *pRichEdit, HBITMAP hBitmap); //底层的一个InsertBitmap
- /*-----------------------------------------------------------------------------
- * 函数名 :Init
- *
- * 功能 :初始化函数,用来指定表情的数目,表情符号等信息
- *
- * 用法 :
- CString pSymbol[] = {":)", ":(", ";)", ":0", ";-)"};
- UINT nIDBmp[] = { IDB_BITMAP1, IDB_BITMAP2, IDB_BITMAP3, IDB_BITMAP4, IDB_BITMAP5};
- m_FaceEdit.Init(5, pSymbol, nIDBmp);
- *
- -----------------------------------------------------------------------------*/
- void CFaceEdit::Init(int nfaceCount, CString *pSymbol, UINT *pIDBmp)
- {
- m_nfaceCount = nfaceCount;
- m_pSymbol = new CString[m_nfaceCount];
- m_pIDBmp = new UINT[m_nfaceCount];
- for(int n=0; n<m_nfaceCount; n++)
- {
- m_pSymbol[n] = pSymbol[n];
- m_pIDBmp[n] = pIDBmp[n];
- }
- }
- /*-----------------------------------------------------------------------------
- * 函数名 :Init
- *
- * 功能 :初始化函数,用来指定表情的数目,表情符号等信息
- *
- * 用法 :
- CString pSymbol[] = {":)", ":(", ";)", ":0", ";-)"};
- CString pBmpFile[] = { "C:\a.bmp", "C:\b.bmp", "C:\c.bmp", "C:\d.bmp", "C:\e.bmp"};
- m_FaceEdit.Init(5, pSymbol, pBmpFile);
- *
- -----------------------------------------------------------------------------*/
- void CFaceEdit::Init(int nfaceCount, CString *pSymbol, CString *pBmpFile)
- {
- m_nfaceCount = nfaceCount;
- m_pSymbol = new CString[m_nfaceCount];
- m_pBmpFile = new CString[m_nfaceCount];
- for(int n=0; n<m_nfaceCount; n++)
- {
- m_pSymbol[n] = pSymbol[n];
- m_pBmpFile[n] = pBmpFile[n];
- }
- }
- /*-----------------------------------------------------------------------------
- * 函数名 :SetText
- *
- * 功能 :类的主要工作函数。该函数负责将str中的符号翻译成表情,显示到
- * CRichEditCtrl中。参数二bEnableFace是功能开头,当它为FALSE时,
- * 本函数将不会翻译表情。
- -----------------------------------------------------------------------------*/
- bool CFaceEdit::SetText(CString str, BOOL bEnableFace)
- {
- if(bEnableFace)
- {
- SetTextWithFace(str);
- }
- else
- {
- SetWindowText(str);
- }
- return true;
- }
- /*-----------------------------------------------------------------------------
- * 函数名 :SetTextWithFace
- *
- * 功能 :实现插入图象的算法函数。
- * 实现原理:
- 假设:CString pSymbol[] = {":)", ":(", "#", "AK47", ":-)"};
- 先将包括表情符号的文本( 如:"haha:)" )直接显示到CRichEditCtrl中,
- 然后选定其中的表情符号( 如:":)" ),再调用InsertBitmap函数
- 实现插入,详见注释
- -----------------------------------------------------------------------------*/
- void CFaceEdit::SetTextWithFace(CString str)
- {
- USES_CONVERSION; //使用A2W宏
- //将上面的数组全部转换成wstring类型的
- wstring *wstrFace = new wstring[m_nfaceCount];
- TRACE("用户定义的表情符号:n");
- for(int n = 0; n<m_nfaceCount; n++)
- {
- TRACE("m_pSymbol[%d]:%sn", n, m_pSymbol[n]);
- wstrFace[n] = A2W(m_pSymbol[n]);
- }
- wstring wstrText(A2W(str));
- SetWindowText(str);
- int nFaceCount = 0; //wstrText中共有多少个表情。
- stFace faceNode; //faceNode中存储的是在哪个位置插入,插入哪一个表情。
- vector <stFace> vecFace; //vecFace[0]表示第一个表情的位置和型号、vecFace[1]表示第二个表情的位置和型号…
- /* *****************************************************************************************
- * 第一步:
- * 在wstrText中查找表情字符(wstrFace)。
- *
- * 如wstrText = "我们的:-)明天更美好AK47,一定:-)非常美好#。"。那么以下操作将生成四个
- * stFace(定义见FaceEdit.h)结点,它们的值分别为{3, 3, 3}, {15, 3, 4}, {10, 1, 3}, {21, 0, 1}。
- * 使用vector数组vecFace进行存储。
- *
- * ****************************************************************************************/
- for(int i=0, m = -1; i<m_nfaceCount; i++)
- {
- //关键的一步:查找宽字符,汉字算一个字符。放在循环中,就可以查找重复的字符。
- while(1)
- {
- m = (int)wstrText.find(wstrFace[i], m + 1); //循环搜索,不放过重复的表情
- if(m != -1)
- {
- faceNode.nPos = m;
- faceNode.nFaceIndex = i;
- faceNode.nLength = (int)wstrFace[i].length();
- vecFace.push_back(faceNode);
- //TRACE("push():%dn", m);
- nFaceCount++;
- }
- else
- {
- break;
- }
- }
- } //查找完毕
- if(nFaceCount==0) //在wstrText中没找到一个表情,下面就无需插入表情了。
- return;
- delete []wstrFace;
- /* *****************************************************************************************
- * 第二步:
- * 使用泛型算法sort进行排序。
- *
- * 上面的四个结点:A:{3, 3, 3}, B:{15, 3, 4}, C:{10, 1, 3}, D:{21, 0, 1},显然这不是按照
- * 顺序排的,这里应该按表情在文本中出现的次序依次替换,否则替换算法将会非常麻烦。
- *
- * ****************************************************************************************/
- bool less_than(stFace &face1, stFace &face2); //声明排序的"条件"函数
- sort(vecFace.begin(), vecFace.end(), less_than); //详见我的ObjectSort工程中的说明。可参见《Essential C++》P84
- /* *****************************************************************************************
- * 第三步:
- * 调整各表情字符位置(nPos)。
- *
- * 排序之后各结点:A:{3, 3, 3}, C:{10, 1, 3}, B:{15, 3, 4}, D:{21, 0, 1}。
- * 经过摸索,发现这样一个规律:
- * 本结点应该向前挪的值(prev) = 上一个表情的长度(prevLength) - 1 + 上一个结点应该向前挪的值(prev)
- *
- * 如:
- CString pSymbol[] = {":)", ":(", "#", "AK47", ":-)"};
- 序号: 0 1 2 3 4
- "我们的:-)明天更美好AK47,一定:-)非常美好#。"
- 位置: 3 11 18 25
- "#"(25, 2, 1) "AK47"(11, 3, 4) ":-)"(3, 4, 3) ":-)"(18, 4, 3)
- ~~ ~~ ~~ ~~
- 排序后:
- ":-)"(3, 4, 3) "AK47"(11,3, 4) ":-)"(18, 4, 3) "#"(25, 2, 1)
- ~~ ~~ ~~ ~~
- 处理后:
- ":-)"(3, 4, 3) "AK47"(9, 3, 4) ":-)"(13, 4, 3) "#"(18, 2, 1)
- ~~ ~~ ~~ ~~
- 少了0 少了2 少了5 少了7
- 3-1+0 4-1+2 3-1+5
- *
- *
- * ****************************************************************************************/
- #ifdef _DEBUG
- TRACE("排序之后:n");
- for(int x = 0; x<nFaceCount; x++)
- {
- TRACE("vecFace[%d].nPos = %dn", x, vecFace[x].nPos);
- }
- #endif //_DEBUG
- for(int t = 0, prevLength = 0, prev = 0; t<nFaceCount; t++)
- {
- vecFace[t].nPos -= prev;
- prevLength = vecFace[t].nLength;
- prev = prevLength - 1 + prev;
- }
- #ifdef _DEBUG
- TRACE("移位处理之后:n");
- for(int k = 0; k<nFaceCount; k++)
- {
- TRACE("vecFace[%d].nPos = %dn", k, vecFace[k].nPos);
- }
- #endif //_DEBUG
- /* *****************************************************************************************
- * 第四步:
- * 下面插入表情。
- *
- * 调用InsertBitmap插入各处理完成的各结点A:{3, 3], C:{9, 1}, B:{13, 3}, D:{18, 0}。
- *
- * ****************************************************************************************/
- try
- {
- for(int j=0; j<nFaceCount; j++)
- {
- stFace faceNode = vecFace[j];
- InsertBitmap(faceNode);
- }
- }
- catch(char *sError)
- {
- MessageBox(sError, "HBITMAP", MB_OK | MB_ICONERROR);
- }
- }
- //泛型算法sort()的排序条件函数,实现按stFace.nPos域排序
- bool less_than(stFace &face1, stFace &face2)
- {
- return face1.nPos < face2.nPos ? true : false;
- }
- //应用层的InsertBitmap
- void CFaceEdit::InsertBitmap(stFace &face)
- {
- int nBegin = face.nPos;
- int nEnd = nBegin + face.nLength;
- SetSel(nBegin, nEnd);
- HBITMAP bmp = NULL;
- if(m_pIDBmp != NULL)
- //从资源创建HBITMAP
- bmp = ::LoadBitmap(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(m_pIDBmp[face.nFaceIndex]));
- else
- //从文件创建HBITMAP
- bmp = (HBITMAP)::LoadImage(NULL, m_pBmpFile[face.nFaceIndex], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
- if(bmp==NULL)
- {
- throw "无效的HBITMAP类型。rnrn可能的原因是:rn位图文件的路径不正确。";
- }
- ::InsertBitmap(this, bmp);
- }
- /*--------------------------------------------------------------------------
- * 函数名:InsertBitmap
- *
- * 功能 :底层的一个InsertBitmap,使用OLE容器,向CRichEditCtrl中插入表情。
- * 根据位图句柄创建OleCreateStaticFromData();用这个函数可以把资源中的图片插入到文本框中
- *
- * 头文件:<Richole.h>、<afxodlgs.h>
- --------------------------------------------------------------------------*/
- void InsertBitmap(CRichEditCtrl *pRichEdit, HBITMAP hBitmap) //底层的一个InsertBitmap
- {
- 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;
- pRichEdit->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 = pRichEdit->GetIRichEditOle()->InsertObject( &reobject );
- delete pDataSource;
- }