窗体的Alpha通道透明色支持
參考:?http://www.delphibbs.com/delphibbs/dispq.asp?lid=2190768
Windows?2000后,為了支持類似MAC界面的Alpha通道混合效果,提供了GDI+,提供了很多的界面功能函數,可以實現很好的界面效果。例如可以使用UpdateLayeredWindow來實現窗體的顏色透明。但是一旦?Form?被定義為利用?LayeredWindow?,窗口的繪圖不再響應沿用多年的?WM_Paint?消息。?
UpdateLayeredWindow(hwnd:HWND;?//?窗口句柄?
????????????????????hdcDst:HDC;?//?目標?DC?
????????????????????ptDst:pPoint;?//?目標的?TopLeft?
????????????????????Size:pSize;?//?顯示?Size?
????????????????????hdcSrc:HDC;?//?源?DC?
????????????????????ptSrc:pPoint;?//?源?DC?的?TopLeft?
????????????????????crKey:COLORREF;?//?透明顏色值?
????????????????????Blend:pBlendFunction;?//?Alpha?混合函數?
????????????????????dwFlags:DWord?//?一組標志位常量?
????????????????????);?
這個函數不但可以設置?Alpha?Blend?,還可以完成類似本例中的異形窗口顯示。標志常量有以下幾個:?
??ULW_COLORKEY?=?$00000001;?//?透明顏色設置是需要的?
??ULW_ALPHA?=?$00000002;?//?Alpha?混合是需要的?
??ULW_OPAQUE?=?$00000004;?//?保持不透明?
不管設置哪些常量,首先與?SetLayeredWindowAttributes?函數一樣,?
需要對窗口設置一個新的擴展風格標志:WS_EX_LAYERED?。?
設置窗口的擴展標志,只對?Windows2000?以上操作系統有效,設置方法與設置普?
通窗口風格的方法一樣:?
SetWindowLong(Handle,?GWL_EXSTYLE,?GetWindowLong(Handle,GWL_EXSTYLE)???
\or? WS_EX_LAYERED?//?增加這個標志?
?????????????);?
注意:如果設置了Alpha?混合標志,必須提供?BlendFunction?的值。?
??PBlendFunction?=?^TBlendFunction;?
??TBlendFunction?=?packed?record?
????BlendOp:?BYTE;?//?取值可以為?AC_SRC_OVER?
????BlendFlags:?BYTE;?//?必須是?0?
????SourceConstantAlpha:?BYTE;?//?取值為希望得到的?Alpha?的值?
????AlphaFormat:?BYTE;?
??end;?
下面的代碼演示如何實現窗體上面某個顏色為全透明,并可以穿透鼠標,效果圖如下:
代碼如下(Delphi?6):
procedure?TForm1.FormCreate(Sender:?TObject);
begin
??Color?:=?clWhite;
??TransparentColor?:=?True;
??TransparentColorValue?:=?clWhite;
end;
這個比較簡單,但是實際上還是用的上面的函數,察看Forms.pas單元就知道了。當然也可以使用圖片來做效果:即設計一張合適的圖片,然后使用上面的方法即可作出一個不規則的圖片窗體出來,非常簡單!!
function?UpdateLayeredWindow(hWnd:?HWND;
??hdcDst:?HDC;?Dst:?PPoint;?const?size:?PSize;
??hdcSrc:?HDC;?Src:?PPoint;
??crKey:?COLORREF;
??pblend:?PBlendFunction;
??dwFlags:?DWORD):?BOOL;?stdcall;?external?'user32.dll';
procedure?ColorUpdateLayeredWindow(Wnd:?HWND;?BMP:?TBitmap;?TransColor:?TColor);
var
??R:?TRect;
??S:?TSize;
??P:?TPoint;
begin
??GetWindowRect(Wnd,?R);
??P?:=?Point(0,?0);
??S.cx?:=?Bmp.Width;
??S.cY?:=?Bmp.Height;
??SetWindowLong(Wnd,?GWL_EXSTYLE,?GetWindowLong(Wnd,?GWL_EXSTYLE)?or?WS_EX_LAYERED);
??UpdateLayeredWindow(Wnd,?0,?@R.TopLeft,?@S,?Bmp.Canvas.Handle,?@P,?TransColor,?0,?ULW_COLORKEY);
end;
procedure?AlphaUpdateLayeredWindow(Wnd:?HWND;?Bmp:?TBitmap;?Alpha:?Byte);
var
??P:?TPoint;
??R:?TRect;
??S:?TSize;
??BF:?_BLENDFUNCTION;
begin
??GetWindowRect(Wnd,?R);
??P?:=?Point(0,?0);
??S.cx?:=?Bmp.Width;
??S.cY?:=?Bmp.Height;
??bf.BlendOp?:=?AC_SRC_OVER;
??bf.BlendFlags?:=?0;
??bf.SourceConstantAlpha?:=?Alpha;
??bf.AlphaFormat?:=?AC_SRC_ALPHA;
??SetWindowLong(wnd,?GWL_EXSTYLE,?GetWindowLong(wnd,?GWL_EXSTYLE)?or?WS_EX_LAYERED);
??UpdateLayeredWindow(wnd,?0,?@R.TopLeft,?@S,?Bmp.Canvas.Handle,?@P,?0,?@BF,?ULW_ALPHA);
end;
procedure?TForm1.FormCreate(Sender:?TObject);
var
??BMP:?TBitmap;
??GB:?TGPBitmap;
??h:?HBITMAP;
begin
??Bmp?:=?TBitmap.Create;
??Bmp.LoadFromFile('F:\password.bmp');
//??GB?:=?TGPBitmap.Create('F:\水晶圖標\1.png');
//??GB.GetHBITMAP(0,?h);
//??Bmp.Handle?:=?h;
//??AlphaUpdateLayeredWindow(Handle,?Bmp,?200);
??ColorUpdateLayeredWindow(Handle,?Bmp,?Bmp.TransparentColor);
??Bmp.Free;
//??GB.Free;???
end;
使用上面得ColorLayeredWindow函數,就可以使BMP作為一個通透的窗口出來,上面的方式不支持Alpha混合,因此對PNG之類的支持不好。使用AlphaLayeredWindow可以支持Alpha通道。如果要支持PNG圖片,可以使用GDI+,也可以使用TPNGObject來讀取PNG圖片,下面代碼使用GDI+,需要使用GDIPAPI和GDIPObj兩個單元,這兩個單元Google一把到處可以找到。
使用上面的方法,窗體上面的控件都需要自己繪制,否則不可見了,但是實際上是在的,可以響應事件等。
?
可惜上面的方法不能使窗體的某些部分半透明,設置AlphaBlend和AlphaBlendValue又會使所有的窗體部分半透明,達不到要求的效果,而且那種透明效果不太好,不能實現Alpha通道效果。那么如何實現下面的效果呢?
要實現這個效果,不知道XDeskWeather是如何實現的,但是使用SGlass可以做到窗體透明效果。
procedure?TForm1.FormCreate(Sender:?TObject);
var
???b?:?TBitmap;
???h?:?HBITMAP;
???gb:?TGPBitmap;
begin
??BorderStyle?:=?bsNone;
??Image1.Picture.LoadFromFile('F:\[2508]水晶圖\[16]警告類\1.png');
??with?TStainedGlass.Create(Self)?do
??begin
????AltTransparency?:=?100;
????//BackStyle?:=?bsCentered;
????BackStyle?:=?bsMosaic;
????DelayTime?:=?1;
????b?:=?TBitmap.Create;
//????gb?:=?tgpbitmap.Create('F:\[2508]水晶圖\[16]警告類\1.png');
//????gb.GetHBITMAP(0,?h);
//????b.Handle?:=?h;
????//Glyph?:=?b;
??end;
end;
需要GDIPlus和SGlass,PNGImage的支持,你也可以使用前面的GDI+的方法,這樣不需要PNGImage。附件中有SGlass單元。
?附:XDeskWeather使用了GDI+,采用了Raize控件和PNGImage,采用PNGImage里面的TPNGObject來支持PNG圖片。PNGImage非常好用,和JPEG庫類似,自己使用一下就知道了。XDeskWeather的透明效果是不是GDI+來實現的,問過作者,沒有反應。??:-(
?
據說XDesk采取兩個窗體來實現的,一個透明作為背景,另外一個是普通的窗體。
---------------------------------------
2005,6月10號又翻出來XDeskWeather看了一下,找到它的資源文件,于是又決心研究一下,發現點擊它的About對話框的背景的時候,其設置對話框中的控件會失去焦點,這樣很明顯是兩個不同的窗體才會出現的情況,因此決定按兩個窗口的方式來實現一下,結果發現原來如此簡單~~~~~~:兩個窗口,一個背景,一個前臺,控制同步移動即可!
結論:
使用Layer窗口,可以使用WM_PRINTCLIENT消息。最重要牢記一點:所有的窗口的更新都必須以圖片方式提供給UpdateLayeredWindow函數!例如,你可以在你的窗口Active的時候,Move的時候,或者鼠標移動到你的控件的時候,在后臺繪制一個圖片,包括你的界面操作變化等,都需要更新圖片,最后使用UpdateLayeredWindow函數更新這個位圖即可!
轉載于:https://www.cnblogs.com/MaxWoods/p/3295867.html
總結
以上是生活随笔為你收集整理的窗体的Alpha通道透明色支持的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Objective-C设计模式(MVC)
- 下一篇: C# 汉字转拼音(全拼)