各位大虾,现在遇到一个问题,做了一个透明的窗体,想在上面画图,以便对下面窗体的内容做一个直观的标注.现在问题是,窗体透明后,在这个窗体上的线也跟着透明了.请问:
如何在一个半透明的窗体内画出不透明的线,如果谁知道怎么能直接在屏幕内任意画图最好,就是在某种条件下,不和屏幕中的任何程序相关的在屏幕中画图.

解决方案 »

  1.   

    窗体的Alpha通道透明色支持参考: http://www.delphibbs.com/delphibbs/dispq.asp?lid=2190768Windows 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单元。PS:越來越佩服自己,現在用BAIDU來混分,BS一下.
      

  2.   

    没人知道丫,老大们给点idea啦...
      

  3.   

    我的想法比较简单,
    就是得到这个窗体的handle,直接划线。
    如果桌面是那个窗体那么
    procedure TForm1.Button1Click(Sender: TObject);
    var
    dc:hdc;
    mc:tcanvas;
    begin
    dc:=getdc(0);
    mc:=Tcanvas.Create;
    mc.Handle:=dc;
    mc.MoveTo(3,3);
    mc.Pen.Color:=clred;
    mc.LineTo(45,113);
    end;