資料准備
- WS_EX_TRANSPARENT | WS_EX_LAYERED
- WM_NCHITTEST & return HTTRANSPARENT
- SetLayeredWindowAttributes(…)
- UpdateLayeredWindow(…)
旁征博引
窗口類型
- Overlapped Windows
- Pop-up Windows
- Child Windows
- Layered Windows \\分層窗口(這是我們這節課研究的重點)
- Message-Only Windows \\消息窗口
分層窗口詳解:
Using a layered window can significantly improve performance and visual effects for a window that has a complex shape, animates its shape, or wishes to use alpha blending effects. The system automatically composes and repaints layered windows and the windows of underlying applications. As a result, layered windows are rendered smoothly, without the flickering typical of complex window regions. In addition, layered windows can be partially translucent, that is, alpha-blended.
這段大概就是說,layered窗口能夠改善顯示效果,給你的窗體加個alpha通道,可以平滑半透明地顯示。嗯,還可以設置為一部分透明一部分不透明的樣子。(據我研究,應該還能設置成漸變透明。)
To create a layered window, specify the WS_EX_LAYERED extended window style when calling the CreateWindowEx function, or call the SetWindowLong function to set WS_EX_LAYERED after the window has been created. After the CreateWindowEx call, the layered window will not become visible until the SetLayeredWindowAttributes or UpdateLayeredWindow function has been called for this window. Note that WS_EX_LAYERED cannot be used for child windows.
一旦你指定了這個屬性,剛開始這個窗體是不能顯示的,你得先設置整個窗體的Alpha通道。通過這兩個函數SetLayeredWindowAttributes、UpdateLayeredWindow 。
值得一提的的是這個不能用於子窗體(也就是不能和WS_CHILD共存唄)。
To set the opacity level or the transparency color key for a given layered window, call SetLayeredWindowAttributes. After the call, the system may still ask the window to paint when the window is shown or resized. However, because the system stores the image of a layered window, the system will not ask the window to paint if parts of it are revealed as a result of relative window moves on the desktop. Legacy applications do not need to restructure their painting code if they want to add translucency or transparency effects for a window, because the system redirects the painting of windows that called SetLayeredWindowAttributes into off-screen memory and recomposes it to achieve the desired effect.
嗯,這段說實話以我高一的英語水平也沒看太懂。大致意思就是,系統可能仍然會給你發送WM_PAINT,但是請注意,系統會自動幫你半透明。你不需要更改任何代碼就能夠實現半透明效果。
總的來說就是:除非程序中調用了InvalidateRect之類的函數,否則系統將接管窗口的繪制,用戶收不到WM_PAINT消息!
For faster and more efficient animation or if per-pixel alpha is needed, call UpdateLayeredWindow. UpdateLayeredWindow should be used primarily when the application must directly supply the shape and content of a layered window, without using the redirection mechanism the system provides through SetLayeredWindowAttributes. In addition, using UpdateLayeredWindow directly uses memory more efficiently, because the system does not need the additional memory required for storing the image of the redirected window. For maximum efficiency in animating windows, call UpdateLayeredWindow to change the position and the size of a layered window. Please note that after SetLayeredWindowAttributes has been called, subsequent UpdateLayeredWindow calls will fail until the layering style bit is cleared and set again.
這段 很重要! 這倆函數是互相沖突的!想為窗口的每個像素設置Alpha通道你就直接調用UpdateLayeredWindow ,請不要調用SetLayeredWindowAttributes. 如果你想要重置,那就清除WS_EX_LAYERED然后重新設置!Hit testing of a layered window is based on the shape and transparency of the window. This means that the areas of the window that are color-keyed or whose alpha value is zero will let the mouse messages through. However, if the layered window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and the mouse events will be passed to other windows underneath the layered window.
碰撞測試(就是測試你的鍵鼠操作是不是落在這個窗體上)取決於你的透明度!也就是說:透明度為完全透明的窗體部分會被“穿透”。如果你想要整個窗體都被“穿透”,請設置WS_EX_TRANSPARENT屬性!
——Come From MSDN
WM_NCHITTEST & return HTTRANSPARENT
了解這一部分的時候請注意了:這一部分不能實現穿透功能(准確的說是他的穿透功能很有限)。
首先我們先了解一下這個 WM_NCHITTEST 是什么玩意兒:
The WM_NCHITTEST message is sent to a window in order to determine what part of the window corresponds to a particular screen coordinate. This can happen, for example, when the cursor moves, when a mouse button is pressed or released, or in response to a call to a function such as WindowFromPoint. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse.
這個消息主要用於幫助系統判斷窗體的哪一部分被點到了,哪一部分被操作了。
它的返回值有一條是這樣的:
HTTRANSPARENT
In a window currently covered by another window in the same thread (the message will be sent to underlying windows in the same thread until one of them returns a code that is not HTTRANSPARENT).
這段我也不翻譯了,相信你也注意到了“in the same thread ”已經連續出現了兩次了!微軟到底在強調什么呢…….呵呵
SetLayeredWindowAttributes
函數說明:
BOOL SetLayeredWindowAttributes( __in HWND hwnd, __in COLORREF crKey, __in BYTE bAlpha, __in DWORD dwFlags );\\這函數用於設置窗口的alpha混合(不透明度)\\實現出來的效果是整個窗體都以某一透明度顯示
函數參數:
hwnd [in] HWND Handle to the layered window. A layered window is created by specifying WS_EX_LAYERED when creating the window with the CreateWindowEx function or by setting WS_EX_LAYERED via SetWindowLong after the window has been created.
擁有WS_EX_LAYERED 屬性的窗口句柄。
crKey [in] COLORREF COLORREF structure that specifies the transparency color key to be used when composing the layered window. All pixels painted by the window in this color will be transparent. To generate a COLORREF, use the RGB macro.
具體說起來又要長篇大論了,簡單來說就是透明窗體的底色是什么??我們不需要底色,只需要能夠看到該窗體下面的另一個窗體,我們就可以忽略這個參數。
bAlpha [in]
BYTE Alpha value used to describe the opacity of the layered window. Similar to the SourceConstantAlpha member of the BLENDFUNCTION structure. When bAlpha is 0, the window is completely transparent. When bAlpha is 255, the window is opaque.
該值為0全透明,該值為255不透明。為什么是255呢??
該參數是BYTE類型 只有8位可存儲來着 你把 11111111 轉換為十進制就是255。
dwFlags [in] DWORD Specifies an action to take. This parameter can be one or more of the following values.
指定哪個參數我們使用了,因為我們忽略了crKey參數,所以我們僅僅指定LWA_ALPHA就可以了。
LWA_COLORKEY
Use crKey as the transparency color.
LWA_ALPHA
Use bAlpha to determine the opacity of the layered window.
函數返回:
BOOL
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
不解釋,你懂得。
需要注意:
Note that once SetLayeredWindowAttributes has been called for a layered window, subsequent UpdateLayeredWindow calls will fail until the layering style bit is cleared and set again.
什么?你問我這一段意思是什么????那就請你重頭認真看我的教程,不要走馬觀花!
UpdateLayeredWindow
函數說明:
BOOL UpdateLayeredWindow( __in HWND hwnd, __in HDC hdcDst, __in POINT *pptDst, __in SIZE *psize, __in HDC hdcSrc, __in POINT *pptSrc, __in COLORREF crKey, __in BLENDFUNCTION *pblend, __in DWORD dwFlags )\\該函數更新分層窗口的位置、大小、形狀、內容、透明度
函數參數:
hwnd [in] HWND Handle to a layered window. A layered window is created by specifying WS_EX_LAYERED when creating the window with the CreateWindowEx function.
hdcDst [in] HDC Handle to a DC for the screen. This handle is obtained by specifying NULL when calling the function. It is used for palette color matching when the window contents are updated. If hdcDst is NULL, the default palette will be used.
輸出到的DC句柄(GetDC(NULL)),你也可以寫NULL使用默認調色盤(不改變內容)。
If hdcSrc is NULL, hdcDst must be NULL.
pptDst [in] POINT Pointer to a POINT structure that specifies the new screen position of the layered window. If the current position is not changing, pptDst can be NULL.
更新位置信息(寫NULL表示不移動)
psize [in] SIZE Pointer to a SIZE structure that specifies the new size of the layered window. If the size of the window is not changing, psize can be NULL. If hdcSrc is NULL, psize must be NULL.
更新大小信息(寫NULL表示不縮放)
hdcSrc [in] HDC Handle to a DC for the surface that defines the layered window. This handle can be obtained by calling the CreateCompatibleDC function. If the shape and visual context of the window are not changing, hdcSrc can be NULL.
內容信息(用於更新窗口顏色)
pptSrc [in] POINT Pointer to a POINT structure that specifies the location of the layer in the device context. If hdcSrc is NULL, pptSrc should be NULL.
從hdcSrc的哪個位置開始更新?
crKey [in] COLORREF COLORREF structure that specifies the color key to be used when composing the layered window. To generate a COLORREF, use the RGB macro.
這個,同上個函數。
pblend [in] BLENDFUNCTION Pointer to a BLENDFUNCTION structure that specifies the transparency value to be used when composing the layered window.
用於更新alpha(我們將在下面給出詳解)
dwFlags [in] DWORD This parameter can be one of the following values.
同上個函數
ULW_ALPHA
Use pblend as the blend function. If the display mode is 256 colors or less, the effect of this value is the same as the effect of ULW_OPAQUE.
ULW_COLORKEY
Use crKey as the transparency color.
ULW_OPAQUE
Draw an opaque layered window.
If hdcSrc is NULL, dwFlags should be zero.
函數返回:
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero.
需要注意:
- 更新一次就像永久更改了整個窗體的位圖一樣
- 效率較低
- 系統自動重新繪制
- 沒有WM_PAINT
最后是極其重要的內容:BLENDFUNCTION參數的講解:
基本概念:
BLENDFUNCTION結構體
AlphaBlend是Window自帶的GDI函數,在作GUI的時候為了達到更漂亮的效果我們常常用它。
這種結構的混合控制通過指定源和目標位圖的混合功能。
typedef struct _BLENDFUNCTION {
BYTE BlendOp;
BYTE BlendFlags;
BYTE SourceConstantAlpha;
BYTE AlphaFormat;
} BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;
BlendOp 指定源混合操作。目前,唯一的源和目標的混合方式已定義為AC_SRC_OVER;
BlendFlags 必須是0;
SourceConstantAlpha 指定一個alpha透明度值,這個值將用於整個源位圖;該SourceConstantAlpha值與源位圖的每個像素的alpha值組合;如果設置為0,就會假定你的圖片是透明的;如果需要使用每像素本身的alpha值,設置SourceConstantAlpha值255(不透明);
AlphaFormat 這個參數控制源和目標的解析方式,AlphaFormat參數有以下值:
AC_SRC_ALPHA: 這個值在源或者目標本身有Alpha通道時(也就是操作的圖本身帶有透明通道信息時),提醒系統API調用函數前必須預先乘以alpha值,也就是說位圖上某個像素位置的red、green、blue通道值必須先與alpha相乘。例如,如果alpha透明值是x,那么red、green、blue三個通道的值必須乘以x並且再除以255(因為alpha的值的范圍是0~255),之后才能被調用。
應用備注:
1、當AlphaFormat參數的值是AC_SRC_ALPHA,那么源位圖必須是32位深,否則的話,AlphaBland函數將調用失敗
2、當BlendOp參數是AC_SRC_OVER時,源位圖根據alpha透明度值直接覆蓋在目標位圖之上
3、如果源位圖不帶有透明度信息(那樣的話,AC_SRC_ALPHA不設置),將由SourceConstanAlpha的值來決定如何混合源位圖與目標位圖,如下表中所示。表中SCA代表SourceConstantAlpha的值,同樣,SCA除以了255,因為它的范圍是從0到255.
Dst.Red = Src.Red * (SCA/255.0) + Dst.Red * (1.0 - (SCA/255.0))
Dst.Green = Src.Green * (SCA/255.0) + Dst.Green * (1.0 - (SCA/255.0))
Dst.Blue = Src.Blue * (SCA/255.0) + Dst.Blue * (1.0 - (SCA/255.0))
在這種情況下,如果目標位圖有透明度信息,那么混合方式將按照下面的公式來:
Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0))
4、如果源位圖沒有用SourceConstantAlpha參數值(那表示該參數等於255),每一個像素的透明度將決定源位圖和目標位圖的混合結果,如下所示:
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue
在這種情況下,如果如果目標位圖有透明度信息,那么混合方式將按照下面的公式來:
Dest.alpha = Src.Alpha + (1 - SrcAlpha) * Dst.Alpha
5、如果源位圖既有SourceConstantAlpha值(也就是它的值不是255),每個像素又有透明度值,那么源位圖的每一個像素將首先乘以SourceConstantAlpha的值,然后根據每個像素的透明度值混合,如下表中所示。同樣,SourceConstantAlpha除以了255,因為它的范圍是從0到255.
Src.Red = Src.Red * SourceConstantAlpha / 255.0;
Src.Green = Src.Green * SourceConstantAlpha / 255.0;
Src.Blue = Src.Blue * SourceConstantAlpha / 255.0;
Src.Alpha = Src.Alpha * SourceConstantAlpha / 255.0;
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue
Dst.Alpha = Src.Alpha + (1 - Src.Alpha) * Dst.Alpha
——該部分來自《百度百科》
現在重點來了!
=>!!!前方高能請注意!!!<=
透明漸變&鼠標穿透的實現方法,實現效果如圖:
=》傳送門《=



