zoukankan      html  css  js  c++  java
  • 窗体的Alpha通道透明色支持 (转载)

    http://www.360doc.com/content/11/0424/15/5131150_111970536.shtml

    参考: 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函数更新这个位图即可!

    窗体的 Alpha 通道透明色支持

    http://bbs.znpc.net/viewthread.php?tid=333

    如何在一个半透明的窗体内画出不透明的线,或者能直接

    http://www.plm.hk/phpgm/thread-3730-1-1.html

  • 相关阅读:
    SpringMVC处理请求
    SpringMVC的启动
    数据结构
    Collections工具类
    位运算
    web应用
    spring Environment
    servlet及jsp之间的请求转发
    spring AOP
    Spring 事件
  • 原文地址:https://www.cnblogs.com/chulia20002001/p/2043741.html
Copyright © 2011-2022 走看看