UpdateLayeredWindow函数是用hdcSRC(也就是PNG图片)画布内容覆盖掉hdcDEST(也就是你的窗口)内容弄出来的效果,所以窗口整个内容被图片全部覆盖掉是正常的并不是你的控件不存在了,不信你放个大Button,写个Click事件试试就知道了。查看MSDN上UpdateLayeredWindow帮助发现
UpdateLayeredWindow always updates the entire window. To update part of a window, use the traditional WM_PAINT and set the blend value using SetLayeredWindowAttributes.
意思是:UpdateLayeredWindow总是更新整个窗口,如果想更新窗口的一部分请使用传统的WM_PAINT消息并用SetLayeredWindowAttributes函数设置Alpha透明值。
所以我写了如下代码:
var
Form1: TForm1;
BMP: TBitmap;
...
procedure TForm1.FormShow(Sender: TObject);
begin
//Must set as Layered window before calling SetLayeredWindowAttributes
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
if not SetLayeredWindowAttributes(Handle, 0, 150, LWA_ALPHA) then
ShowMessage('failed');
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Draw(0, 0, BMP);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle:= bsNone;
BMP:= TBitmap.Create;
BMP.LoadFromFile('ball.bmp');
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
BMP.Free;
end;
结果发现窗口是透明了,但是图片和控件也跟着透明了!我是希望窗口全透明、图片半透明、控件不透明。难道在WM_PAINT消息里做手脚?
总结一下:
UpdateLayeredWindow: 窗口全透明了,但是控件被图片覆盖了
SetLayeredWindowAttributes:窗口和控件的透明度一样了!
SetLayeredWindowAttributes把窗口和控件的透明度弄成一样了,这样层次感不明显效果不好,还是UpdateLayeredWindow显示的图片透明效果好!问题是UpdateLayeredWindow把窗口上控件都用图片盖住了,只要想办法把所有控件放到另外个窗口上再Show在UpdateLayeredWindow窗口的前面也许就行了,说不定人家说的用两个窗口重叠显示的说法是对的,于是接着创建了2个窗口Form1、Form2,Form1上放了1个按钮,改写小雨哥代码:
//====================Form1代码=======================
unit Unit1;
// 请勿删除代码来源声明 www.01cn.net
// 请勿发到 playicq . . 小雨哥
{ 借花献佛,小雨哥不会见怪吧!
Modified by delcomp in 05/12/2005
Modified by man8888 2007-9-30
这里显示的图片必须是从带Alpha透明的PNG图片转换来的BMP}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
Bitmap:TBitmap;
procedure LayeredWindow(wnd: THandle; Bmp: TBitmap; Alpha: Byte);
public
procedure WMNCHitTest(var Message: TWMNCHitTest);message WM_NCHitTest;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.DFM}
procedure TForm1.WMNCHitTest(var Message: TWMNCHitTest);
begin
inherited;
Message.Result := htCaption; // 获得鼠标点击移动的效果
end;
procedure TForm1.WMPaint(var Message: TWMPaint);
begin
//这个函数不会被执行!因为调用了UpdateLayeredWindow
inherited;
end;
procedure TForm1.LayeredWindow(wnd: THandle; Bmp: TBitmap; Alpha: Byte);
var
Pt: TPoint;
//ARect: TRect;
Size: TSize;
bf: TBlendFunction;
begin
{MSDN:
UpdateLayeredWindow always updates the entire window. To update part of a window,
use the traditional WM_PAINT and set the blend value using SetLayeredWindowAttributes.
}
//set the parameter of BlendFunction , refer to the MSDN
bf.BlendOp := AC_SRC_OVER;
bf.BlendFlags := 0; // 必须是 0
bf.SourceConstantAlpha := Alpha; //透明度
bf.AlphaFormat := AC_SRC_ALPHA;
//GetWindowRect(wnd, ARect);
Pt:= Point(0, 0);
Size.cx:= Bmp.Width;
Size.cY:= Bmp.Height;
//对窗口设置新的扩展风格标志
SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
//调用 UpdateLayeredWindow 获得需要的异型窗口
if not UpdateLayeredWindow(
wnd,
GetDC(0),
nil,
@Size,
Bmp.Canvas.Handle,
@Pt,
0,
@bf,
ULW_ALPHA) then
ShowMessage('Call Failed!');
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Alpha:Byte;
begin
Bitmap:= TBitmap.Create;
Bitmap.LoadFromFile('ball.bmp');
Alpha:= 255; // 图片 Alpha 值
LayeredWindow(Handle, Bitmap, Alpha);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Bitmap.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
close;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
//在另外窗口上显示本窗口的控件。因为 UpdateLayeredWindow覆盖本窗口所有内容
Button1.Parent:= Form2;
Form2.show;
end;
end.
//====================Form2代码=======================
procedure TForm2.FormCreate(Sender: TObject);
begin
//隐藏窗口,但是按钮等还显示
BorderStyle:= bsNone;
Brush.Style:= bsClear;
end;
哈哈!按钮和图片果然都显示出来啦!Alpha透明效果也非常好!但是有BUG,点按钮后后面的图片窗口不见了,大家帮忙改善一下!:)