向Richedit插入動態Gif的實現(關於QQ表情功能的製做)

向Richedit插入動態Gif的實現(關於QQ表情功能的製做)

要作一個相似QQ表情的東西,用BCB6.0來作,原本這個工具也不是熟悉,用得多仍是VC吧,難! html

上網查了一下,由於要播放GIF文件,那個在CSDN說的幾乎都是說用QQ的ImageOle來作,而後就是一大堆的連接,說哪里哪里有的,怎樣引用法 程序員

可是版權啊 服務器

並且全都是05年的帖子,奇怪了,難道是百度的錯,仍是如今沒有人作這個了 框架

無耐,繼續百度 google, ide

找到了一位哥們作的 函數

相似 MSN 信息發送框的製做(上)
http://www.vckbase.com/document/viewdoc/?id=1087 工具

惋惜啊,不能顯示GIF 並且那個表情的選擇面板也不太對勁,都是用Button來作的,圖片多了那不是慢得要死,這種方法不可取吧 oop

決定學習如何作一個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(); return 0; } 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(); return 0; } // 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開發顯示GifActiveX控件

baseMSDN:開發語言-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"

初始化COMGDI+

在對話框初始化的時候建立控件,並設置屬性等。

編譯運行成功。

6   添加事件

第二步已經支持鏈接點,idl文件裏會有事件接口

6.1 爲事件接口添加函數(聲明)

類視圖-右鍵點擊lib接口裏的事件接口-添加-方法,添加一個Click函數,參數爲long型的xy座標。產生的效果是,在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 設置屬性

修改對話框,增長新控件等等。而後處理數據變化,例如:處理EditEN_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不是個好東西!!!

 

第一次寫博客,還給博客嚇了一跳,覺得保存到草稿箱的找不出來的呢,哈哈!

相關文章
相關標籤/搜索