[返回]
计算机世界2000年第28期

制作半透明窗口

松本电工实业有限公司电脑部 舒嵩嵩

  用过金山词霸的朋友,一定会为其半透明的翻译提示窗口而称奇。究竟这种窗口是如何做出来的呢?下面我们将探讨这种半透明窗口的制作方法。

一、 原 理

  首先,我们先从透明窗口说起,其实透明窗口就是可以透过窗口看到背景,所以,我们可以将窗口后面的背景图像显示在窗口前面,实现透明窗口的效果。至于半透明的效果,是在透明的基础上,加上一层滤镜,使看到的背景模糊一点而已。所以,在拿到背景图像后,先在该图像加上一层滤镜(把图像弄模糊),然后再显示在窗口上,就能达到半透明的效果。

  我们可归纳出实现半透明窗口的步骤:在窗口显示前获取背景图像→ 对背景图像进行滤镜效果处理 → 将处理过的背景图像显示在窗口前面。

  1.获取背景图像

  要获取背景图像,先用GetDC(0)函数获取整个屏幕设备场景(DC),再用CopyRect函数拷贝窗口的背景到指定的Tbitmap,该Tbitmap就是我们所要的图像了。其中函数GetDC(0)取得的DC可用TCanvas.Handle保存;而CopyRect 是TCancas类的成员函数,作用是从一个Canvas中拷贝一指定区域(Rect)到另一个Canvas 的指定区域。

  2.对背景图像进行滤镜效果处理

  用循环的方法遍历图像的每一点,将各点的某些频段的光波滤除。其实,滤镜种类繁多,所以算法亦很多,读者可参考相关资料,选择您满意的方法。本文的滤镜是灰色的,实现方法见 TranslucentBmp(Bmp:TBitmap;AColor:TColor;
ATransparent:Longint)。其中,参数Bmp是要处理的图像,AColor是滤镜的颜色,ATransparent是透明度。

二、 编写程序

  将以上原理用Delphi编写成程序。在Delphi中新建一个 Project,Form1的Height和Width分别设成150和300(不要做得太大,不然显示速度很慢),再设置BorderStyle的值为bsNone;在Form1中添加一个Timage控件Image1,将其 Align属性设成alClient。再添加一个标签Label1和按钮TSpeedButton,在Label1的Caption 属性中输入“这是一半透明窗口!”,按钮的Caption属性设成“x”,在其OnClick事件中输入一行“Close;”,并将它们Bring to Front。另外,可添加四个TShape,贴在Image1 的四边上,以构造Form1的3D效果,如图1。各控件的属性如下表:

  完整的源代码如下:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs,StdCtrls, ExtCtrls, Buttons;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Shape1: TShape;
    Shape2: TShape;
    Shape3: TShape;
    Shape4: TShape;
    Image1: TImage;
    SpeedButton1: TSpeedButton;
    procedure FormCreate(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
  private
    { Private declarations }
    //截获背景图像
    function  GetBackgroundBmp:TBitmap;
    //对背景图像进行滤镜处理
procedure TranslucentBmp(Bmp:TBitmap;
AColor:TColor;ATransparent:Longint);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
//以下截获背景图像
function TForm1.GetBackgroundBmp:TBitmap;
var Scn:TCanvas;
 h,w:Integer;
begin
 Scn:=TCanvas.Create; //建立整个屏幕的画布
 h:=ClientHeight;     //窗口的高
 w:=ClientWidth;      //窗口的宽
 Result.Height:=h;    //设返回位图的高就是窗口的高
 Result.Width:=w;     //设返回位图的宽就是窗口的宽
 try
Scn.Handle:=GetDC(0);//取得整个屏幕的DC
//以下一行将窗口的背景部分复制到指定的
//画布中,也就是本函数的返回值
     Result.Canvas.CopyRect(Rect(0,0,w,h),
      Scn,Rect(Left,Top,Left+w,Top+h));
     ReleaseDC(0, Scn.handle);
     finally
     Scn.Free;
     end;
end;

//以下函数对背景图像进行滤镜处理,
//Bmp是要处理的位图;ATransparent是透明度
procedure TForm1.TranslucentBmp
(Bmp:TBitmap;AColor:TColor;ATransparent:Longint);
var BkColor:COLORREF;
    ForeColor:Longint;
    R,G,B:Int64;
    i,j:Integer;
begin
     ForeColor:=ColorToRGB(AColor);
     with Bmp.Canvas do
     for i:=ClientHeight-1 downto 0 do
        for j:=ClientWidth-1 downto 0 do
        begin
           BkColor:=GetPixel(Handle,j,i); //取得每一像素
           R:=Byte(ForeColor)+(Byte(BkColor)
           -Byte(ForeColor))*ATransparent;
           G:=Byte(ForeColor shr 8)+(Byte
           (BkColor shr 8)-Byte(ForeColor shr 8))
             *ATransparent;
           B:=Byte(ForeColor shr 16)+(Byte
              (BkColor shr 16)
            -Byte(ForeColor shr 16))*ATransparent;
           SetPixelV(Handle,j,i,RGB(R,G,B));//合成像素
        end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var BackgroundBmp:TBitmap;
begin
     try
     BackgroundBmp:=Tbitmap.Create;
       //建立窗口背景图
   BackgroundBmp.PixelFormat:=pf24bit;
      //指定该图是24位真彩色
BackgroundBmp:=GetBackgroundBmp; 
 //取得窗口背景图
     TranslucentBmp(BackgroundBmp,clBlack,50);
     //对该图像进行滤镜处理
Image1.Picture.Bitmap:=BackgroundBmp;
 //将处理过的图像显示出来
     finally
     BackgroundBmp.Free;
     end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
     Close;
end;

end.

  程序的运行效果如图2所示。

三、 结束语

  需要说明的是:由于受到以上滤镜算法的速度影响,窗口显示时有所延迟,在窗口频繁显示和关闭时不是很流畅。但不知读者朋友们有没有发现,金山词霸的半透明窗口效果只能在带MMX指令集的处理器中才起作用,所以笔者大胆推测,金山词霸的半透明窗口是经过MMX的多媒体指令集进行优化的,这样它才可以达到理想的效果。有兴趣的朋友可以试一下,说不定您做得比金山词霸还好呢。

  以上程序在中文Windows 98、Delphi 4 C/S环境下编译通过。