SetLayeredWindowAttributes函數:
hwnd是透明表單的控制代碼,
crKey為顏色值,
bAlpha是透明度,取值範圍是[0,255],
dwFlags是透明方式,可以取兩個值:
當取值為LWA_ALPHA時,crKey參數無效,bAlpha參數有效;
當取值為LWA_COLORKEY時,bAlpha參數有效而表單中的所有顏色為crKey的地方將變為透明。
LWA_ALPHA = 0x2 LWA_COLORKEY=0x1
要使使表單擁有透明效果,首先要有WS_EX_LAYERED擴充屬性 (舊的sdk沒有定義這個屬性,所以可以直接指定為0x80000). WS_EX_LAYERED = 0x80000
Windows 2000作業系統無論是在品質上還是在使用者介面上都有了很大的改善與提高,使用者對系統的操作變的更加簡單、方便,感覺也更加舒
適。如果使用者在使用時留意一下,不難發現其中介面上的一些新特性。例如,Windows 2000提供了對帶陰影阿爾法混合游標的支援、提供對菜單
、提示框淡入淡出效果的支援以及在外殼拖拽具有阿爾法混合片等透明特效。所有這些特效看似不同但實際都是通過對Windows 2000新提
供的一個多層式視窗API函數的調用而實現的。 既然是Windows 2000系統提供的API函數,那麼也就意味著在自己的應用程式中同樣能夠實現該函
數做做支援的各種特效。
在程式設計時,有時一些微小的改善就足以增強使用者介面的顯示效果。例如,使用一個具有阿爾法混合效果的游標顯然要比一隻普通游標的
感覺要好的多,尤其是在大螢幕顯示器或多顯示器系統下這種游標也更容易找到。更進一步,顯示器的螢幕大小是有限的,如果想同時查看多個
視窗的內容顯然是不太方便的,儘管採取大螢幕顯示器或多顯示器系統能在一定程度上緩解但遠不如將這些應用程式表單設定為透明或半透明來
的徹底和方便。顯示的兩個應用程式雖然存在覆蓋,但位於前台的程式表單顯然沒有影響後台Word文檔內容的顯示。鑒於多層式視窗函數在程
序設計中的實用作用,本文將對其作具體的介紹以充分挖掘其潛力並將其應用到程式設計中去。
多層式視窗
在介紹多層式視窗函數之前,首先要介紹一下WS_EX_LAYERED擴充視窗風格。該視窗風格也是Windows 2000新增加的,如果使用了該屬性,窗
體將具備複合形狀、動畫、阿爾法混合等方面的視覺特效。
視窗通過被其他視窗的裁剪而在螢幕上以矩形出現。為了實現一個圓形表單,僅僅簡單繪製一個圓形表單是不夠的,這樣的話系統還會把窗
體按原矩形進行點擊檢測,而且位於該表單下的視窗仍將被該表單矩形所裁剪。或許可以考慮在園形表單顯示出來前取得位於該表單矩形下可視
地區的快照,並在稍後表單顯示完畢後將其繪製到當前表單。但由於其他視窗能夠繪製該表單覆蓋下的地區,而前景程式無法獲知這種繪製將於
何時發生而不會及時擷取下面可視地區的新的快照,因此這種解決方案並不能在多進程、多任務環境下很正常的工作。對於這種情況,在
Windows 95/98和Windows NT 4.0下的正確做法是通過SetWindowRgn()API函數指出需要的表單形狀,但是這種處理在頻繁更改表單形狀或是在
螢幕上拖拽時仍有缺陷存在:前台表單將要求位於其下的表單重繪整個地區,這將生過多的訊息和計算量。而且使用SetWindowRgn()只能實現
表單的全透明而無法實現半透明效果。或許這也正是多層式視窗被提出的原因。
多層式視窗真正實現了兩個截然不同的概念:分層和重新導向。為了能夠去除任何一個層,WS_EX_LAYERED標誌位必須要設定,這可以在表單創
建時設定也可以在建立後通過以GWL_EXSTYLE標誌調用SetWindowLong()來進行設定。接下來,可以通過UpdateLayeredWindows()函數來更新
多層式視窗。在具體使用時,需要在位元影像中繪製出可視地區,並將其與關鍵色、阿爾法混合參數等一起提供給UpdateLayeredWindows()函數。需
要注意的是,在使用UpdateLayeredWindows()函數時,應用程式並不需要響應WM_PAINT或其他繪製訊息。
除此之外,還可以使用傳統的Win32繪製機制來實現,這需要調用另一個API函數SetLayeredWindowAttributes()來完成對關鍵色或阿爾法
混合參數值的設定。一旦該函數被調用,系統將開始為多層式視窗重新導向所有的繪製並自動應用指定的特效。
表單半透明特效的實現
前面已經對多層式視窗做了較為詳細的介紹。這裡將對SetLayeredWindowAttributes()函數及其使用方法做具體的介紹,並在此基礎上實現
表單半透明特效。首先給出SetLayeredWindowAttributes()原形:
BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window 透明表單的控制代碼
COLORREF crKey, // specifies the color key 顏色值
BYTE bAlpha, // value for the blend function 透明度,取值範圍是[0,255]
DWORD dwFlags // action 透明方式,可以取兩個值:
當取值為LWA_ALPHA時,crKey參數無效,bAlpha參數有效;
當取值為LWA_COLORKEY時,bAlpha參數有效,而表單中的所有顏色為crKey的地方將變為透明。
LWA_ALPHA = 0x2
LWA_COLORKEY=0x1
);
其中dwFlags有LWA_ALPHA(值為2)和LWA_COLORKEY(值為1)兩種設定,如果LWA_ALPHA被設定的話,通過bAlpha參數指定表單的透明度;
如果LWA_COLORKEY標誌被設定的話,則指定關鍵色為crKey,該顏色所覆蓋的地區將從表單去除,去除後的地區將不再進行點擊檢測,其他顏色
則正常顯示。如果阿爾法混合值設定為0,其視窗地區同樣不進行點擊檢測。
前面說過,SetLayeredWindowAttributes()函數是Windows 2000新增的一個API函數,它所在的模組為USER32.DLL。在用GetModuleHandle
()裝載USER32.DLL模組並調用GetProcAddress()得到函數 SetLayeredWindowAttributes()在User32.dll中的指標後就可以通過
SetLayeredWindowAttributes()函數將表單設定為半透明了:
// 全域變數
typedef BOOL (WINAPI *lpfn) (HWND hWnd, COLORREF cr, BYTE bAlpha, DWORD dwFlags);
lpfn g_pSetLayeredWindowAttributes;
……
// 擷取函數 SetLayeredWindowAttributes 在User32.dll中的指標
HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));
g_pSetLayeredWindowAttributes = (lpfn)GetProcAddress(hUser32, "SetLayeredWindowAttributes");
if (g_pSetLayeredWindowAttributes == NULL)
::PostQuitMessage(0);
這段代碼通常在程式初始化時運行以及時將USER32.DLL模組裝載到記憶體並擷取得到SetLayeredWindowAttributes()函數指標。在程式退出
前需要通過FreeLibrary()函數釋放先前載入的模組:
// 卸載模組
if (m_hUser32 != NULL)
FreeLibrary(m_hUser32);
在將表單設定為半透明時,首先要擷取得到該表單的視窗控制代碼,以指明要操作的是哪一個視窗。如果是對本應用程式中的某個視窗進行設定
,可以通過傳遞視窗控制代碼或是用GetSafeHwnd()來動態擷取。如果要對本程式外的某個程式視窗進行設定,一般的做法是通過對FindWindow(
)函數的調用來擷取指定視窗標題的視窗控制代碼。在得到視窗控制代碼之後並不能直接調用SetLayeredWindowAttributes()進行設定,需要在
GetWindowLong()擷取得到當前視窗風格設定後在其基礎之上添加WS_EX_LAYERED擴充風格,並通過SetWindowLong()函數將其設定:
// 半透明
HWND hWnd = GetSafeHwnd();
LONG lWindowLong = GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED;
::SetWindowLong(hWnd, GWL_EXSTYLE, lWindowLong);
g_pSetLayeredWindowAttributes(hWnd, 0, (BYTE)m_sldAlpha.GetPos(), 2);
::RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
為了能夠使用該函數,還必須在上述語句之前添加預定義語句:
#define WS_EX_LAYERED 0x00080000
異形表單特效的實現
使用SetLayeredWindowAttributes()建立異形表單是非常簡單的,具體過程與半透明表單的實現極為類似,所不同的只是將標誌設定為
LWA_COLORKEY並指定需要透明顯示的關鍵色:
// 指定關鍵色
HWND hWnd = GetSafeHwnd();
LONG lWindowLong = GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED;
::SetWindowLong(hWnd, GWL_EXSTYLE, lWindowLong);
g_pSetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 0, 1);
::RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
小結
本文通過對Windows 2000新增API函數SetLayeredWindowAttributes()的使用非常簡單的實現了表單的半透明設定和異形表單的建立。除
了SetLayeredWindowAttributes()函數,Windows 2000還提供了其他許多類似的特效函數比如用於表單動態滑動顯示的AnimateWindow()。
由於這些函數是系統提供的API函數,因此不會受程式設計語言的制約,也就是說,並不只在VC++下可以實現上述特效。在C++ Builder、Delphi等其
他開發環境下也是可以用類似的方法來實現的。本文所述程式碼在Windows 2000 Professional下由Microsoft Visual C++ 6.0編譯通過