向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,終于是做好了,上個圖
?
還有很多東西要做啊
總結
以上是生活随笔為你收集整理的向Richedit插入动态Gif的实现(关于QQ表情功能的制作)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IIS漏洞
- 下一篇: 高数下(同济大学版本)期中冲刺式复习