注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

珠海渔郎之电子网档

项目管理 + 程序开发 + Delphi + 电脑应用 + 数码 + 进化感悟

 
 
 

日志

 
 

窗体的Alpha半透明源代码  

2009-11-25 13:12:57|  分类: Delphi |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

支持XDeskWeather About类似效果的Alpha半透明。效果很酷。

窗体的Alpha半透明源代码 - 珠海渔郎 - 珠海渔郎之电子网档

Kingron原创,包含源代码和资源文件。

窗体的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+来实现的,问过作者,没有反应。 :-(


窗体的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函数更新这个位图即可!

  评论这张
 
阅读(706)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017