使用duilib開發半透明異形表單程式(附源碼和demo),duilibdemo
轉載請說明原出處,謝謝~~:http://blog.csdn.net/zhuhongshu/article/details/43532791
半透明異形表單的功能在之前維護的老版本的duilib裡面已經有了基本的功能,但是因為一直存在較多的缺陷,所以我一直建議少用,就連我自己寫仿酷狗項目也只是在幾個小地方用了半透明異形表單。不過今天在群裡和其他幾位朋友討論後,發現了之前的許多問題以及解決方案。所以我立馬修複了當前的庫,並且寫了一個半透明異形表單的demo來測試效果。這裡的半透明表單是用UpdateLayeredWindow函數實現的,並不是雙層表單。
在這篇部落格裡,我主要說明一下一下幾點:
1、之前版本使用半透明異形表單存在的一些問題
2、新版本裡的大致解決方案
3、還沒有完全解決的地方
4、使用半透明異形表單應該注意的地方
廢話不多說,先把demo的展示一下:
存在的問題和解決辦法:
問題1:字型穿透
這是之前的半透明表單的最大問題,由於GDI本身的缺陷,導致渲染文字時缺少透明通道資訊,導致文字穿透,之前使用heat群主的alpha修複方法,但是還不能完全解決這個問題。為此我把文字渲染函數修改。當表單是透明模式或者使用者開啟了gdi+文字渲染模式,就用gdi+來渲染文字。開啟半透明模式的方法是設定xml布局的Window標籤的bktrans屬性為true。開啟gdi+文字渲染模式的方法是設定xml布局的Window標籤的gdiplustext屬性為true。bktrans屬性和gdiplustext屬性是獨立的。(如果感覺預設的GDI文字渲染效果不夠好時,就可以使用gdiplustext屬性得到更好的渲染效果)。
GDI+的渲染效率是出名的低,不過據我測試文字渲染才用GDI+的話看不出影響效率。
問題2:字型穿透2
還是字型穿透的文字,即使把文字渲染改成gdi+再配合alpha修複,但是依然發現會出現字型穿透的問題,這也是之前讓我納悶的地方。而今天我做了許多測試後發現,原來和控制項的背景色有關。如果不設定控制項的背景色或者背景色是半透明的,渲染文字就不會穿透,而設定了背景色而且不透明就會穿透,背景色填充是CRenderEnghine類的DrawColor函數負責的。觀察源碼後發現。如果背景色的透明度設定為FF(也就是不透明)的話,就會使用GDI函數來填充背景色,而如果設定了透明度,則使用AlphaBlend函數來使用一個位元影像來填充背景。所以問題還是出在透明通道上(說明alpha修複還不能完全解決相關的問題)。
所以只要讓duilib填充背景色時包含透明資訊就不會導致穿透了,而後閱讀代碼發現duilib預設的alpha背景色填充代碼比較多。我個人感覺不如直接用gdi+來填充背景色。代碼如下:
if( color <= 0x00FFFFFF ) return;Gdiplus::Graphics graphics( hDC );Gdiplus::SolidBrush brush(Gdiplus::Color((LOBYTE((color)>>24)), GetBValue(color), GetGValue(color), GetRValue(color)));graphics.FillRectangle(&brush, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
這個代碼比較簡單,應該不會影響效率吧?
問題3:表單重新整理不完整
原來的庫編譯的半透明異形程式,有時會出現表單重新整理不完整的情況,比如:把一個半透明程式的一般拖到螢幕外側,然後雙擊標題列讓他最大化,接著再最小化,然後把程式再拖到螢幕內,就會發現原來在螢幕外部的介面完全沒有繪製出來。
導致這個問題的原因,是因為要使用異形表單就需要使用UpdateLayeredWindow函數,而使用了這個函數後表單的繪製就由UpdateLayeredWindow來接管了,許多情況下WM_PAINT訊息就不會觸發。跟蹤代碼後發現是因為程式還原後調用GetUpdateRect函數擷取更新地區資訊時資訊不完整導致的。所以我在CManagerUI類中攔截了WM_SYSCOMMAND訊息,發現程式從最大化還原後就設定m_bIsRestore為真,把m_bIsRestore作為標誌。當在WM_PAINT中重新整理介面時如果m_bIsRestore為真則重新整理整個程式介面而不只是GetUpdateRtect擷取的地區。
還沒有完全解決的地方
前面說明的一些問題解決後,配合alpha修複的代碼。基本就可以使用半透明異形表單了。不過還是存在一些沒有解決的問題:
1、半透明模式下Edit控制項的效果不好。duilib的Edit控制項內部調用了Win32的edit控制項,為了在半透明模式下使用它,不得不使用WS_POPUP樣式表單Win32的edit控制項。但是這樣表單後會在外觀上出現一些問題。就是單擊duilib的Edit控制項時會閃一下。所以建議使用RichEdit控制項來代替Edit,而且RichEdit控制項是支援半透明或者全透明背景的。
2、RichEdit控制項雖然可以正常使用,但是由於他內部渲染文字時沒有處理透明通道,所以會導致文字穿透。出現文字穿透的現象只有在RichEdit控制項完全無背景色或者背景圖片的情況下。
使用半透明異形表單應該注意的地方
目前需要注意的就是RichEdit控制項的使用,如果讓RichEdit直接暴露在全透明的地方,文字渲染就會有問題。如果RichEdit設定了背景色或者背景色,或者他的父控制項設定了背景色背景圖,則全完沒有問題。不過好在,應該沒有什麼地方需要讓RichEdit直接暴露在全透明的位置。前面發的的文字框就是用RichEdit做的。
如果使用RichEdit的時候發現了穿透現象,建議更換textcolor的值或者bkcolor的值來修複問題。
總結:
由於這次修改的地方比較多,設計的檔案和代碼也比較亂,我就沒辦法單獨的提供某個源檔案了。具體的修改可以通過svn來對比新版本和舊版本的代碼來得知。源碼和demo我都更新到了我的庫中,支援duilib和uilib:點擊開啟連結
Redrain 2015.2.5