关于制作透明窗体(100分)

  • 主题发起人 主题发起人 yuboo
  • 开始时间 开始时间
Y

yuboo

Unregistered / Unconfirmed
GUEST, unregistred user!
在网上和杂志上经常看到关于制作透明窗体的文章,大多是加载窗体前复制好窗体下面的<br>图像,移动窗体时计算好相对位置后向窗体上拷贝。但当图像改变后就露馅了,而且代码<br>也很长。有没有一种简单的方法实现呢?我看到过一篇VB的文章是用的这三个API函数:<br>SetWindowRgn,CombineRgn和CreateRectRgn来实现的。不知Delphi是如何用API函数实现的?<br>能否写的具体一些?或写信告诉我:fox21th@sina.com多谢!
 
制作透明窗体只要将form.cavas.brush.style设置成bsclear就可以了。<br>而制作不规则窗体就需要用你所说的三个函数,setwindowrgn(handle,<br>CreateEllipticRgn(0,0,400,300),true)将建立一个椭圆窗体。其余的你可以看相应帮助。
 
实现窗体透明,主要是拦截CMEraseBkgnd消息,并将窗体画刷的Style属性设为bsClear。<br>下为简单的例子:<br>Procedure CMEraseBkgnd(var Message:TWMEraseBkgnd);Message WM_ERASEBKGND;<br>begin<br>&nbsp; brush.style := bsClear;<br>&nbsp; Inherited;<br>end;
 
SetWindowRgn,CombineRgn和CreateRectRgn是用于创建任意形状的窗口,<br>不是用于使窗口透明的。
 
概念问题!<br>真正的透明或者是半透明窗体应该是可以透过窗体本身的可见部分看到后面的背景,<br>也就是其他窗体或是桌面。这个必然要通过alpha混合来实现,目前只有在win2000<br>下可以真正实现,因为有api支持,win9x下只能模拟,效果不太好,就象金山词霸<br>的取词窗口,背景改变而窗体上还是不变,就象你说的那种技术。
 
pino说的对。
 
用Win2000<br>新的API函数制作透明窗口 <br><br>--------------------------------------------------------------------------------<br><br>---- Windows2000增加了很多功能,起码修改TCP/IP设置后无需重新启动电脑就可以使用的特性就会使很多以前饱受WIN95/98重新启动并扫描文件之苦的用户觉得Windows2000 确实有了改进。除此之外,Windows2000的API也有很多新的东西。下面一个例子是利用 Windows2000新的API函数制作透明窗口。这里主要介绍用Delphi调用Windows2000新的 API函数实现这一功能的过程。 <br><br>----使用SetLayeredWindowAttributes API函数可以设置窗口的风格,该函数介绍如下: <br><br>函数功能:设置窗口透明颜色<br>格式:BOOL SetLayeredWindowAttributes(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HWND hwnd, &nbsp; &nbsp; &nbsp; &nbsp; //窗口手柄<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;COLORREF crKey, &nbsp; &nbsp;//指定颜色值<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;BYTE bAlpha, &nbsp; &nbsp; &nbsp; &nbsp;//混合函数值<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DWORD dwFlags &nbsp; &nbsp; //动作<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;);<br><br>----参数解释: <br><br>----hwnd <br><br>---- 窗口手柄。当使用CreateWindowEx函数创建窗口时,窗口由WS_EX_LAYERED指定的值创建;或者窗口已经创建后,由SetWindowLong根据 WS_EX_LAYERED指定的值改变。 <br><br>----crKey <br><br>----指向一个COLORREF值,该值指定一个透明颜色值,当创建窗口时,窗口将使用该值。窗口绘制的所有颜色将为透明。要想产生COLORREF值,请使用RGB宏。 <br><br>----bAlpha <br><br>----混合函数值。该值用于描述窗口的不透明度。当bAlpha 值为0时,窗口完全透明,当bAlpha值为255时,窗口完全不透明。 <br><br>---- dwFlags <br><br>----指定动作。这个参数可以取一个或多个值: <br><br>&nbsp;<br><br>----返回值: <br><br>----如果函数成功,返回非零值。如果函数失败,返回零值。进一步取得错误信息,请调用GetLastError.函数。 <br><br>----注意:一旦SetLayeredWindowAttributes调用该函数,随后的UpdateLayeredWindow调用将会无效,直到层风格的点被清除并重新设置。 <br><br>---- 各个参数详细意义和它们的取值以及每个值的意义请参看http//msdn.microsoft.com/<br>library/psdk/winui/windows_1p6b.htm,这里不加赘述。这里要强调的是,该函数只适用于Windows2000,要调试本程序,请选Windows2000操作系统。 <br><br>---- 在表单中放置一个ScrollBar控件,使用FormCreate, FormDestroy,ScrollBar1Change三个事件。当移动ScrollBar的按钮时,表单的透明度将产生变化。程序代码如下: <br><br>{API声明}<br>type<br>&nbsp; TSetLayeredWindowAttributes<br>&nbsp; &nbsp; = function(wnd: HWND; crKey: DWORD;<br>&nbsp; &nbsp; &nbsp; bAlpha: BYTE; dwFlag: DWORD): Boolean; stdcall;<br><br>const<br>&nbsp; WS_EX_LAYERED = $80000;<br>&nbsp; LWA_ALPHA = 2;<br><br>var<br>&nbsp; hLibUser32: THandle;<br>&nbsp; MySetLayeredWindowAttributes:<br>&nbsp; &nbsp; &nbsp; TSetLayeredWindowAttributes;<br><br>implementation<br><br>{$R *.DFM}<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>var<br>&nbsp; p: Pointer;<br>begin<br>&nbsp; hLibUser32 := LoadLibraryA(‘user32.dll');<br>&nbsp; MySetLayeredWindowAttributes := nil;<br>&nbsp; if hLibUser32 &lt;&gt; 0 then begin<br>&nbsp;p:=GetProcAddress(hLibUser32, <br>&nbsp; &nbsp; ‘SetLayeredWindowAttributes');<br>&nbsp; &nbsp; if p = nil then begin<br>&nbsp; &nbsp; &nbsp; FreeLibrary(hLibUser32);<br>&nbsp; &nbsp; &nbsp; hLibUser32 := 0;<br>&nbsp; &nbsp; end else begin<br>&nbsp; &nbsp; &nbsp; MySetLayeredWindowAttributes := <br>&nbsp; &nbsp; &nbsp;TSetLayeredWindowAttributes(p);<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>&nbsp; if hLibUser32 &lt;&gt; 0 then begin<br>&nbsp; &nbsp; SetWindowLong(Handle, GWL_EXSTYLE,<br>&nbsp; &nbsp; &nbsp; GetWindowLong(Handle, GWL_EXSTYLE)<br>&nbsp; &nbsp; &nbsp; &nbsp;or WS_EX_LAYERED);<br>&nbsp; &nbsp; ScrollBar1.Position := ScrollBar1.Max;<br>&nbsp; &nbsp; ScrollBar1Change(Self);<br>&nbsp; end else begin<br>&nbsp; &nbsp; ShowMessage(‘该操作系统不支持!');<br>&nbsp; &nbsp; Application.Terminate;<br>&nbsp; end;<br>end;<br><br>procedure TForm1.FormDestroy(Sender: TObject);<br>begin<br>&nbsp; if hLibUser32 &lt;&gt; 0 then begin<br>&nbsp; &nbsp; &nbsp;FreeLibrary(hLibUser32);<br>&nbsp; &nbsp; &nbsp;hLibUser32 := 0;<br>&nbsp; end;<br>end;<br><br>procedure TForm1.ScrollBar1Change(Sender: TObject);<br>var<br>&nbsp; alpha: Integer;<br>begin<br>&nbsp; if hLibUser32 &lt;&gt; 0 then begin<br>&nbsp; &nbsp; alpha := ScrollBar1.Position;<br>alpha := alpha * 255 div <br>&nbsp;(ScrollBar1.Max - ScrollBar1.Min);<br>&nbsp; &nbsp; if alpha &lt; 8 then alpha := 8;<br>&nbsp; &nbsp; if alpha &gt; 255 then alpha := 255;<br>MySetLayeredWindowAttributes<br>(Handle, 0, Byte(alpha), LWA_ALPHA);<br>&nbsp; end;<br>end;<br><br>----程序在Delphi5.0、Wndows2000操作系统下调试成功。 <br>
 
如何制作半透明窗口 <br><br>---- 用过金山词霸的朋友,一定会为其半透明的翻译提示窗口而称奇。究竟这种窗口是如何做出来的呢?下面我们将来探讨这种半透明的窗口的制作方法。 <br><br>一、 原理 <br>---- 首先,我们先从透明窗口说起,其实透明窗口就是可以透过窗口看到它背景。所以,我们可以将窗口后面的背景图象,显示在窗口前面,就可实现透明窗口的效果了。至于半透明的效果,是在透明的基础上,加上一层滤镜,使看到的背景模糊一点而已。所以,在拿到背景图象后,先在该图象加上一层滤镜(把图象弄模糊),然后再显示在窗口上,就能达到半透明的效果。 <br>---- 我们可归纳出实现半透明窗口的步骤:在窗口显示前其获取背景图 → 对背景图象进行滤镜效果处理 → 将处理过的背景图象显示在窗口前面。 <br><br>---- (1) 获取背景图象 <br><br>---- 要获取背景图,先用GetDC(0)函数获取整个屏幕设备场景(DC),再用CopyRect函数拷贝窗口的背景到指定的Tbitmap,该Tbitmap就是我们所要的图象了。其中函数GetDC(0)取得的DC可用TCanvas.Handle保存;而CopyRect是TCancas类的成员函数,作用是从一Canvas中拷贝一指定区域(Rect)到另一Canvas的指定区域。 <br><br>---- (2)对背景图进行滤镜效果处理 <br><br>---- 用循环的方法遍历图象的每一点,将各点的某些频段的光波滤除。其实,滤镜种类繁多,所以的算法亦很多,读者们可参考相关资料,选择您满意的方法。本文的滤镜是灰色的,实现方法见TranslucentBmp(Bmp:TBitmap;AColor:TColor;ATransparent:Longint)。其中,参数Bmp是要处理的图象,AColor是滤镜的颜色,ATransparent是透明度。 <br><br>二、 写程序 <br>---- <br>将以上原理用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效果,如图(一)。各控件的属性如下表:<br><br>组件名称 属性 设置值 <br>Form1 BorderStyle BsNone <br>&nbsp;Height 150 <br>&nbsp;Width 300 <br>&nbsp;TFont 宋体9号 <br>Image1 Align AlClient <br>Label1 Caption 这是一半透明窗口! <br>&nbsp;TFont 宋体9号,黄色 <br>SpeedButton1 Caption X <br>&nbsp;Left 279 <br>&nbsp;Top -1 <br>&nbsp;Height 14 <br>&nbsp;Width 13 <br>&nbsp;Transparent True <br><br><br>&nbsp;<br>图(一) <br>---- 完整的源代码如下: <br><br>unit Unit1;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, <br>Graphics, Controls, Forms, Dialogs,<br>&nbsp; StdCtrls, ExtCtrls, Buttons;<br><br>type<br>&nbsp; TForm1 = class(TForm)<br>&nbsp; &nbsp; Label1: TLabel;<br>&nbsp; &nbsp; Shape1: TShape;<br>&nbsp; &nbsp; Shape2: TShape;<br>&nbsp; &nbsp; Shape3: TShape;<br>&nbsp; &nbsp; Shape4: TShape;<br>&nbsp; &nbsp; Image1: TImage;<br>&nbsp; &nbsp; SpeedButton1: TSpeedButton;<br>&nbsp; &nbsp; procedure FormCreate(Sender: TObject);<br>&nbsp; &nbsp; procedure SpeedButton1Click(Sender: TObject);<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; //截获背景图象<br>&nbsp; &nbsp; function &nbsp;GetBackgroundBmp:TBitmap;<br>&nbsp; &nbsp; //对背景图象进行滤镜处理<br>procedure TranslucentBmp(Bmp:TBitmap;<br>AColor:TColor;ATransparent:Longint);<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br>&nbsp; end;<br><br>var<br>&nbsp; Form1: TForm1;<br><br>implementation<br><br>{$R *.DFM}<br>//以下截获背景图象<br>function TForm1.GetBackgroundBmp:TBitmap;<br>var Scn:TCanvas;<br>&nbsp; &nbsp; h,w:Integer;<br>begin<br>Scn:=TCanvas.Create; //建立整个屏幕的画布<br>h:=ClientHeight;//窗口的高<br>w:=ClientWidth; //窗口的宽<br>Result.Height:=h; &nbsp; &nbsp;//设返回位图的高就是窗口的高<br>Result.Width:=w;//设返回位图的宽就是窗口的宽<br>try<br>Scn.Handle:=GetDC(0);//取得整个屏幕的DC<br>//以下一行将窗口的背景部分复制到指定的画布中,<br>也就是本函数的返回值<br>Result.Canvas.CopyRect(Rect(0,0,w,h),Scn,<br>Rect(Left,Top,Left+w,Top+h));<br>ReleaseDC(0, Scn.handle);<br>finally<br>Scn.Free;<br>end;<br>end;<br><br>//以下函数对背景图象进行滤镜处理,<br>Bmp是要处理的位图;ATransparent是透明度<br>procedure TForm1.TranslucentBmp(Bmp:<br>TBitmap;AColor:TColor;ATransparent:Longint);<br>var BkColor:COLORREF;<br>&nbsp; &nbsp; ForeColor:Longint;<br>&nbsp; &nbsp; R,G,B:Int64;<br>&nbsp; &nbsp; i,j:Integer;<br>begin<br>ForeColor:=ColorToRGB(AColor);<br>with Bmp.Canvas do<br>for i:=ClientHeight-1 downto 0 do<br>&nbsp; &nbsp;for j:=ClientWidth-1 downto 0 do<br>&nbsp; &nbsp;begin<br>&nbsp;BkColor:=GetPixel(Handle,j,i); //取得每一象素<br>&nbsp;R:=Byte(ForeColor)+<br>(Byte(BkColor)-Byte(ForeColor))*ATransparent;<br>&nbsp;G:=Byte(ForeColor shr 8)+<br>(Byte(BkColor shr 8)-Byte(ForeColor <br>shr 8))*ATransparent;<br>&nbsp;B:=Byte(ForeColor shr 16)+<br>(Byte(BkColor shr 16)-Byte(ForeColor <br>shr 16))*ATransparent;<br>&nbsp;SetPixelV(Handle,j,i,RGB(R,G,B));//合成象素<br>&nbsp; &nbsp;end;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>var BackgroundBmp:TBitmap;<br>begin<br>try<br>BackgroundBmp:=Tbitmap.Create; &nbsp;<br>//建立窗口背景图<br>BackgroundBmp.PixelFormat:=pf24bit; &nbsp;<br>//指定该图是24位真彩色<br>BackgroundBmp:=GetBackgroundBmp;<br>//取得窗口背景图<br>TranslucentBmp(BackgroundBmp,clBlack,50);<br>//对该图象进行滤镜处理<br>Image1.Picture.Bitmap:=BackgroundBmp;<br>//将处理过的图象显示出来<br>finally<br>BackgroundBmp.Free;<br>end;<br>end;<br><br>procedure TForm1.SpeedButton1Click<br>(Sender: TObject);<br>begin<br>Close;<br>end;<br><br>end.<br><br>---- 程序的运行效果如图(一)所示。 <br>三、 结束语 <br>---- 需要说明的是:由于受到以上滤镜算法的速度影响,所以窗口显示时有所延迟,在窗口频繁显示和关闭时不是很流畅。但不知读者朋友们有没有发现,金山词霸的半透明窗口效果只能在带MMX指令集的处理器中才起作用,所以笔者大胆推测,金山词霸的半透明窗口是经过MMX的多媒体指令集进行优化的,这样它才可以达到理想的效果。有兴趣的朋友可以试一下,说不定您做得比金山词霸还好呢。 ---- 以上程序在中文Windows 98、Delphi 4 C/S环境下编译通过。 <br>
 
那我所问的那三个函数又如何用呢?
 
拦截CMEraseBkgnd消息,并将窗体画刷的Style属性设为bsClear<br>》不能刷新!W2000的那个函数也只是看过!应该可以的!<br><br>SetWindowRgn &nbsp; 设置窗体的显示区域<br>CombineRgn &nbsp; &nbsp; 获取两个区域的并集<br>CreateRectRgn &nbsp;创建矩形区域<br><br>具体的参数、用法可看帮助!
 
多人接受答案了。
 
后退
顶部