一種快速重新整理richedit中內嵌動畫的方法的實現

2021-09-06 20:50:40 字數 2345 閱讀 7590

在im中使用動畫表情是一種非常有趣的方式,然而選擇一種合適的方式來實現卻並不容易。

1、使用瀏覽器做容器。

2、使用qt提供的richtext做容器。

3、使用richedit做容器。

使用瀏覽器做容器好處是使用簡單,效率應該也不錯(沒有測試,只是感覺),缺點也很明顯:記憶體占用太高,依賴於瀏覽器核心。基於ie核心雖然不需要帶乙個大的安裝包,但ie核心問題不少,有了問題很難解決;webkit核心雖然開源,但是體積寵大。

而要使用qt的richtext則要求程式是基於qt開發,如yy語音。對於一般的客戶端程式來說,qt也還是太大了,而且qt中的richtext能夠實現的功能和windows中的richedit相比也還是略顯單薄。

目前看來在qq中實現的動畫表情重新整理效率應該是最高的,可以看到qq從歷史版本以來就一直堅持使用richedit來顯示聊天內容。

使用richedit的優點很多,和瀏覽器相比如體積小,記憶體占用小,效率在經過適當優化後也可以很高(現在的qq在動畫重新整理上應該是首屈一指的);和qt的richtext相比,不需要依賴qt(這裡只限於windows平台),功能豐富,而且ms也還在不斷推出新版本。

雖然說在qq中使用richedit顯示動畫表情效能不錯,然而不是隨便哪個客戶端開發人員簡單實現乙個ole物件就可以實現的。到底能達到什麼樣的效能還要看最後優化的功力。

說了這麼多,乾貨出場......

我們知道,richedit是乙個ole物件的容器。通過自己實現乙個新的ole物件,就可以實現在richedit中顯示自繪的圖象,當然也包含表情動畫。

動畫要動起來,不外乎定時去重新整理這些ole物件。

要重新整理乙個ole物件,首先需要知道ole物件的位置。

2、在ole物件的ondraw函式中快取物件的繪製位置。

當容器中顯示的表情數量相對較少時,如<100,這時第一種方式簡單有效,但是當顯示物件很多時(如滿屏的小動畫,>1000個),儘管採用兩分法去查詢座標,cpu占用也不簡單。

第二種方法簡單直接,因為物件插入後是要顯示的,一顯示容器就要呼叫ole的ondraw方法來繪製這個ole物件,其中的引數就有顯示位置,只需要在這時把這個位置快取起來即可,不需要每次都去查詢。但是問題也來了,這種方法只知道誰要顯示,不知道誰不要顯示,那麼那些不需要顯示的表情的定時器如何處理呢?

解決這個問題的答案在於乙個由richedit在重新整理時發出來的訊息:en_update。該訊息在richedit每次繪製前都會由richedit send到應用程式。有了這個訊息,我們就可以在視窗重新整理的時候清空那些已經隱藏了的表情的定時器。

到此我們的選擇已經有了,那就是直接快取表情座標。

有了座標如何定時重新整理表情呢?

1、通過invalidaterect來重新整理richedit中表情的位置。

2、直接在richedit中表情顯示位置繪製新的表情幀。

如果同時只顯示少量的表情,採用哪種方法都沒有問題。這裡要解決的同時大量小表情重新整理的問題(如》1000),這個時候髒矩形甚至都變得沒有意義了,基本上都是整個視窗的重新整理。

既然是整個視窗重新整理,採用invalidaterect和自己繪製會有什麼不同嗎?

在昨天以前我也一直不相信這樣乙個殘酷的實現:richedit在重新整理滿屏的小動畫時效率非常低,低到讓你無法忍受(單核cpu可以佔到100%)。查了半天一直不明白瓶頸在哪。

經過不斷排查,最後定位到richedit的渲染問題上:當ole物件很多時,richedit在乙個1920*1020的螢幕上重新整理小表情動畫一次要用掉200ms左右(cpu i5, 2.3g)。通過編譯乙份網上獲得的wince上使用的richedit原始碼並執行,採用intel的vtune分析效能瓶頸發現,在richedit的繪製內容是乙個字串,每個richedit物件在這個字串中以0xfffe代表,要繪製這個ole物件,richedit需要去乙個ole列表中查詢哪乙個ole物件指向當前的0xfffe所在的索引,儘管在查詢時採用兩分法去查詢ole物件的指標,當物件數量比較大時,效率依然非常低下(假定顯示1024個物件,顯示乙個平均查詢10次,那麼就需要1024*10次查詢)。

定位了瓶頸答案就顯而易見了,直接通過richedit的繪製來更新ole顯然物件這樣的場景是不合適的,剩下的就只能是自己繪製表情了。

繪製表情就需要涉及到表情的選擇狀態,背景,及其它一些不需要更新的內容的剪裁等細節問題,只需要做好適當處理即可。

1920×1080:

soui占用3%, qq占用19%。(身邊沒有機器,沒有截圖)

1366*768:soui占用0%, qq占用8%(見下圖)。

一種快速排序演算法

using system class program for int l 0 l src.length l src count temp l i 3 0xff temp l static void main string args watch.stop console.writeline quick...

快速排序的一種實現

閒來沒事,寫了乙個程式玩玩,省的到時候會了shell,又不會c的程式設計了 手動痛哭 本著簡明的原則,選取的標準數是在陣列的 開頭 或者 結尾處 這裡需要注意,如果你選擇的基準數是在左側,那麼就需要從右側開始遍歷陣列 從右側選取的基準數也是同理。include include include usi...

快速排序演算法的一種實現

參考部落格 白話經典演算法系列之六 快速排序 快速搞定 功能 實現快速排序演算法 include 方法宣告 intadjustsort int a,int m,int n void quicksort int a,int m,int n int main void printf 排序前的陣列順序.n...