向Richedit插入动态Gif的实现(关于QQ表情功能的制作)

http://www.cnblogs.com/tony-law/archive/2011/09/16/2178944.html


要做一个类似QQ表情的东西,用BCB6.0来做,本来这个工具也不是熟悉,用得多还是VC吧,难!

上网查了一下,因为要播放GIF文件,那个在CSDN说的几乎都是说用QQ的ImageOle来做,然后就是一大堆的链接,说哪里哪里有的,怎样引用法

但是版权啊

而且全都是05年的帖子,奇怪了,难道是百度的错,还是现在没有人做这个了

无耐,继续百度 google,

找到了一位哥们做的

类似 MSN 信息发送框的制作(上)
http://www.vckbase.com/document/viewdoc/?id=1087

可惜啊,不能显示GIF 而且那个表情的选择面板也不太对劲,都是用Button来做的,图片多了那不是慢得要死,这种方法不可取吧

决定学习如何做一个ATL的com组件,自己实现一下这个组件吧

这时又找到了这篇文章http://blog.csdn.net/wheatfield/article/details/5833532

这篇文章说了很多关于ATL这些相关的内容知识

比如如何插入OLE对象

  

复制代码
TCHAR Filter[]=_T("JGP文件(*.jpg)|*.jpg;*.jpeg|GIF文件(*.gif)|*.gif|BMP文件(*.bmp)|*.bmp|所有文件(*.*)|*.*||");
    CFileDialog dlgOpen(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
    if(dlgOpen.DoModal()==IDOK)
    {
  IRichEditOle* lpRichEditOle = m_RichEdit.GetIRichEditOle(); //m_RichEdit为您的RichEdit对象

  IStorage*  lpStorage  = NULL;//存储接口
  IOleObject*  lpOleObject  = NULL;//OLE对象
  LPLOCKBYTES  lpLockBytes  = NULL;//LOCKBYTE
  IOleClientSite* lpOleClientSite = NULL; 
  CComPtr<IMaiYuanOleImage> IPic;
  CLSID   clsid;
  REOBJECT  reobject;
  HRESULT   hr;


  if(lpRichEditOle == NULL)
   return;
  //创建IMaiYuanOleImage对象并获取接口
  hr = ::CoCreateInstance(CLSID_MYOleImage,NULL,CLSCTX_INPROC,IID_IMaiYuanOleImage,(LPVOID*)&IPic);
  if( IPic == NULL )
  {
   return;
  }

  BOOL bRet = TRUE;

  try{
   hr = IPic->QueryInterface(IID_IOleObject, (void**)&lpOleObject);//获得数据对象接口
if( hr != S_OK ) 
    AfxThrowOleException(hr);
   hr = lpOleObject->GetUserClassID(&clsid);
   if ( hr != S_OK)
    AfxThrowOleException(hr);

   hr = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);//创建LOCKBYTE对象
if (hr != S_OK)
    AfxThrowOleException(hr);
   ASSERT(lpLockBytes != NULL);

   hr = ::StgCreateDocfileOnILockBytes(lpLockBytes,//创建复合文档
    STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
   if (hr != S_OK)
   {
    VERIFY(lpLockBytes->Release() ==0);
    lpLockBytes = NULL;
    AfxThrowOleException(hr);
   }

   lpRichEditOle->GetClientSite(&lpOleClientSite);

   ZeroMemory(&reobject, sizeof(REOBJECT));//初始化一个对象  
   reobject.cbStruct =sizeof(REOBJECT);
   reobject.clsid  = clsid;
   reobject.cp   = REO_CP_SELECTION;
   reobject.dvaspect = DVASPECT_CONTENT;
   reobject.dwFlags = REO_BELOWBASELINE;
   reobject.poleobj = lpOleObject;
   reobject.polesite = lpOleClientSite;
   reobject.pstg  = lpStorage;

   lpOleObject->SetClientSite(lpOleClientSite);//
   hr = lpRichEditOle->InsertObject( &reobject );
   if (hr != S_OK)
    AfxThrowOleException(hr);
   OleSetContainedObject(lpOleObject,TRUE);
   IPic->Load(_bstr_t(dlgOpen.GetPathName())); //装载要显示的图像
  }

  catch( COleException* e )
  {
   TRACE(_T("OleException code:%d"),e->m_sc);
   e->Delete();
   bRet = FALSE;
  }

  // release the interface
  //if( IPic     != NULL )  IPic->Release();
if( lpOleObject  != NULL )  lpOleObject->Release();
  if( lpOleClientSite != NULL ) lpOleClientSite->Release();
  if( lpStorage  != NULL ) lpStorage->Release();

  lpRichEditOle->Release();
 }
复制代码

还有个ATL实现播放GIF的源代码

看了,还明白了如何去做了,但他的实现方式有问题,用线程去做的话,播放几次那个CPU就无限地增大,卡死机

他是用pictureEx那个类来做的,本以为是ipicture这个东西的问题,后来改成了GDI+,image->draw(),但还是出现了这种情况,无耐啊

网上又有人说了,这个可能用定时器来做的话会好一点,

这位仁兄的,不知道是原创还是转载,反正就标着一个原字

ATL 开发ActiveX控件之定时器使用

http://blog.csdn.net/gxulg/article/details/299115

还有这位先生

ATL 开发ActiveX控件之定时器使用(改进,含源码)

http://blog.csdn.net/willnow/article/details/6456106

这个定时器类

复制代码
// CTimer
template <class Derived, class T, const IID* piid>
class CTimer
{
public:
    
    CTimer()
    {
        m_bTimerOn = FALSE;
    }
    
    HRESULT TimerOn(DWORD dwTimerInterval)
    {
        Derived* pDerived = ((Derived*)this);
        
        m_dwTimerInterval = dwTimerInterval;
        if (m_bTimerOn) // already on, just change interval
return S_OK;
        
        m_bTimerOn = TRUE;
        m_dwTimerInterval = dwTimerInterval;
        m_pStream = NULL;
        
        HRESULT hRes;
        
        hRes = CoMarshalInterThreadInterfaceInStream(*piid, (T*)pDerived, &m_pStream);
        
        // Create thread and pass the thread proc the this ptr
        m_hThread = CreateThread(NULL, 0, &_Apartment, (void*)this, 0, &m_dwThreadID);
        
        return S_OK;
    }
    
    void TimerOff()
    {
        if (m_bTimerOn)
        {
            m_bTimerOn = FALSE;
            AtlWaitWithMessageLoop(m_hThread);
        }
    }
    
    
    // Implementation
private:
    static DWORD WINAPI _Apartment(void* pv)
    {
        CTimer<Derived, T, piid>* pThis = (CTimer<Derived, T, piid>*) pv;
        pThis->Apartment();
        return0;
    }
    
    DWORD Apartment()
    {
        CoInitialize(NULL);
        HRESULT hRes;
        
        m_spT.Release();
        
        if (m_pStream)
            hRes = CoGetInterfaceAndReleaseStream(m_pStream, *piid, (void**)&m_spT);
        
        while(m_bTimerOn)
        {
            Sleep(m_dwTimerInterval);
            if (!m_bTimerOn)
                break;
            
            m_spT->_OnTimer();
        }
        m_spT.Release();
        
        CoUninitialize();
        return0;
    }
    
    // Attributes
public:
    DWORD m_dwTimerInterval;
    
    // Implementation
private:
    HANDLE m_hThread;
    DWORD m_dwThreadID;
    LPSTREAM m_pStream;
    CComPtr<T> m_spT;
    BOOL m_bTimerOn;
};
复制代码

 折腾得够惨了,哈哈

无意中也发现了这位兄弟的博客,找不到了地址了

但下载了他的源码,而且还做了一个讲解的PDF,够用心的了,附上他的总结

/*****************************************************

实现 QQ表情这个功能的资料比较缺乏,我也在网上找了比较久,根据网上找到的一些
相关资料,一点点尝试实现的。 
以上所述只是实现 QQ的表情功能的第一步,更深入的内容我也在尝试中,欢迎有兴趣
的网友跟我一起探讨。 
项目工程代码我放在 QQ 群:44177419,70934898,37950043 的群共享上面。需要代码
的可以去那下载,也可以直接发邮件来索取。代码有错误的地方,欢迎发邮件指正。 
我的联系方式: 
QQ:xpmo@qq.com
MSN:msn@msn.com
邮箱:xpmo@qq.com
欢迎转载,不过希望转载时注明出处。 
 *****************************************************/

他的心声跟我一样,资料少啊

另外还有一个介绍 用VS2008+ATL开发Gif的ActiveX控件的步骤

http://blog.csdn.net/crybird/article/details/4049047

/****************************************************************

用VS2008+ATL开发显示Gif的ActiveX控件

base:MSDN:开发语言-VS文档-VC++-参考信息-库参考-ATL-Concepts-ATL Tutorial

1   创建解决方案

创建一个空的解决方案,名称GifSolution。将来包含控件项目和测试项目。

2   创建ATL项目

解决方案视图-右击解决方案-添加-新建项目,弹出的对话框中选ATL项目,名称为GifAnimate确定。弹出的对话框中选择DLL服务器(可选允许合并代理存根,这样不会产生代理dll),完成后编译,这样工程框架就完成了。

3   添加新组件

3.1 一点要说明的

组件分有窗口的和无窗口的,这里应该用有窗口的,所以添加组件的时候,外观不要基于none,最好基于CStatic。因为gif是动态的,应该用另一个线程绘制,这样不影响主线程响应消息,绘图更加流畅。

两种窗口的区别:无窗口的控件用父窗口做自己的窗口;用父窗口的DC绘图;通过DEFAULT_REFLECTION_HANDLER()把消息反馈给父窗口以进行响应。有窗口的控件,多一个CContainedWindow m_ctlStatic变量作为显示窗口;在BEGIN_MSG_MAP / END_MSG_MAP之间,通过ALT_MSG_MAP(1)宏映射消息处理(1为控件m_ctlStatic构造时候的内部标记,因为可能有多个窗口,默认1个,用户可以自己添加)。

3.2 添加组件对象

为GifAnimate项目添加类-选择ATL控件,点击添加,弹出对话框。

第一卡:组件名称GifAniControl

第二卡:支持连接点(因为要通知客户端)

第三卡:默认接口

第四卡:外观基于Static,可插入(在注册表注册为OLE插入对象,可以插入Office)

第五卡:实现固有属性-背景色、边框色、边框可见性

确定后,编译通过。

3.3 为组件添加方法

类视图-右键点击控件接口-添加-方法,分别添加Play Stop Pause Continue PrevFrame NextFrame函数,以操作gif图片。添加IsPlaying函数,添加LoadGifFromFile LoadGifFromStream函数

3.4 为组件添加属性

注意:在idl文件里定义一个枚举,指明播放方向。

 

类视图-右键点击控件接口-添加-属性,分别添加Loop(循环次数) DelayTimeFactor(时间因子) PlayDirection(播放方向)等属性。

 

对于每一个属性,控件类增加了一对函数,去读写属性get/put_XXX,真正的变量要我们自己写的。

4   实现绘图

添加GifImage类,用于实现绘图功能。

在控件类里,添加一个GifImage类型的变量,主要用于对图片的控制。

完成组件接口函数和属性的调用。

把窗口的句柄给GifImage,让它实现绘图。

(对于无窗口控件,修改组件的OnDraw函数,实现绘图)

编译通过就可以测试了(由于用到了GDI+,用ActiveX控件测试容器无法调用函数)。

5   添加测试项目

右键点击解决方案-添加-新建项目,弹出的对话框中选MFC EXE项目,名称GifTestDlg。创建一个基于对话框的项目。

导入DLL:#import "../GifAnimate/Debug/GifAnimate.dll"

初始化COM和GDI+

在对话框初始化的时候创建控件,并设置属性等。

编译运行成功。

6   添加事件

第二步已经支持连接点,idl文件里会有事件接口

6.1 为事件接口添加函数(声明)

类视图-右键点击lib接口里的事件接口-添加-方法,添加一个Click函数,参数为long型的x,y坐标。产生的效果是,在idl文件里,向导为事件接口添加了一个点击函数。

6.2 生成代理类函数

生成一个代理类,实现函数。[Only in VC6, VS2008自动完成]

类视图-右键点击控件类-添加-添加连接点,在对话框选中以上提到的连接点,确定。

代理类会包装一个函数Fire_Click,触发客户端。

6.3 触发事件(调用函数)

响应控件类的WM_LBUTTONDOWN消息,调用代理类的Fire_Click函数。

6.4 客户端关注事件

客户端用ATL或者MFC完成一个接收器GifSink,连接、工作、断开。

7   添加属性页

完全可以不做而通过程序设置属性,做这个是给懒程序员用的,或者只是让组件使用更方便。

7.1 添加属性页卡片

添加-类-ATL属性页-确定,弹出对话框中添加简称,修改组件属性和标题,确定。

系统生成相关的对话框卡片资源、对应对卡片类、idl相关内容、注册脚本等。卡片类有一个Apply函数,用于接受属性设置。

7.2 设置属性

修改对话框,增加新控件等等。然后处理数据变化,例如:处理Edit的EN_CHANGE事件,设置page组件的脏数据标记(修改但没有确定)。最好并完成Apply函数。

7.3 手工把属性页添加到控件

在控件类.h添加如下代码

PROP_ENTRY("Sides", 1, CLSID_GifProp)

8   说明

1.  本文只是举例说明开发过程,抛砖而已。

2.  样例只是框架,不能直接使用,所有代码没有经过测试

3.  样例接收器GifSink和属性页卡片没有完成,懒了,呵呵

4.  样例背景等很多属性没有实现

5.  使用了GDI+,但GDI+的Image类的SetActiveFrame函数有问题,网上貌似没有解决办法。Debug版本不影响使用,Release版本没有测试。如果有兴趣,可以使用IPicture接口,网上很多。

6.  本文和本样例版权crybird所有,引用处请标记crybird.

*****************************************************************************************************

 

说着说着,又找到那位兄弟的博客网址了附上

实现QQ表情功能(1)(2) http://blog.csdn.net/moxiaopeng/article/details/4211839

但经我实践,有错,是在运行时插入成功,但双击那张GIF图片的时候,程序崩溃,但基本上也是按照上面的方法,用定时器去做的,总言之感谢分享!

那些高手都是滴水不漏的啊!

还有最后的QQ表情选择面板

博客园里面也有位同学实现 了,还真不错,感谢了

QQ表情选择面板的VC实现

http://www.cnblogs.com/hoodlum1980/archive/2010/01/09/1642732.html

 

他是用cximage这个库来实现 的,哎呀,BCB里面也可以用,但我怎样试都是链接错误,NND,人品太差了

不过也太大了吧,不爽,应该用GDI+,因为网上也说了BCB里面可以用GDI+

但....

我就是用不了,很多方法了,csdn的老妖也有个说明,如何如何用的

 也给贴上吧

用GDI+实现半透明渐变的特效窗口

http://www.ccrun.com/article.asp?i=643&d=n5u8o4

/**************************************************************************************

方法:在C++Builder中使用GDI+的方法和代码网上遍地都是,这里为了完整性,简单说说流程:

1.) 在BCB6中已自带了ghiplus.h文件,故只需要生成gdiplus.lib文件就可以:
    在命令行下运行implib gdiplus.lib gdiplus.dll。(如果ghiplus.dll不在当前文件夹下,注意写完整路径)

2.) 在工程的编译选项中加入STRICT条件编译:
    Project-->Options-->Directories/Conditionals-->Condtionals-->点击旁边的"..."按钮-->输入STRICT,然后Add。

3.) 在工程中加入Gdiplus.lib:
    Project-->Add To Project-->找到Gdiplus.lib添加进来。

4.) 在工程的.h文件中包含所需的头文件,注意先后顺序:
    #include "math.hpp"
    #include <algorithm>
    using std::min;
    using std::max;
    #include "gdiplus.h"
    using namespace Gdiplus;

 ****************************************************************************/

也按上面的方法做了,也可以在image对象调用draw方法了

但在设置显示帧的时候

 

复制代码
UINT nCount = pImg->GetFrameDimensionsCount();
        GUID* pDimensionIDs =new GUID[nCount];
        pImg->GetFrameDimensionsList(pDimensionIDs, nCount);
        m_nTotalFrame = pImg->GetFrameCount(&pDimensionIDs[0]);
        //PropertyTagFrameDelay是GDI+中预定义的一个GIG属性ID值,表示标签帧数据的延迟时间
        UINT nSize = pImg->GetPropertyItemSize(PropertyTagFrameDelay);
        m_pPropertyItem = (PropertyItem*)malloc(nSize);
        pImg->GetPropertyItem(PropertyTagFrameDelay,nSize,m_pPropertyItem);
复制代码

[Linker Error] Unresolved external '_FrameDimensionTime' referenced from

 

这个你也太欺负人了吧,不是坑爹吗?!

 

我又改成pictureEx那个类的显示GIF,终于是做好了,上个图

 

还有很多东西要做啊

 

哈哈,利用BCB编译的时间来写这个,TMD BCB你也编译得太快了吧

 

总论BCB不是个好东西!!!

 

第一次写博客,还给博客吓了一跳,以为保存到草稿箱的找不出来的呢,哈哈!


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值