请问GDI+PNG做的窗体怎么放置控件? ( 积分: 100 )

  • 主题发起人 主题发起人 lovezyp
  • 开始时间 开始时间
L

lovezyp

Unregistered / Unconfirmed
GUEST, unregistred user!
我用GDI+PNG制作不规则窗体,显示很成功,但是窗体上的控件都不显示,只显示那个不规则窗体,个人认为是PNG图片把他们全覆盖了,怎么样才能显示控件,网上提问此类问题的不少,可是没有回答的!谢谢

关键代码和网上的都差不多
rocedure Tform1.ShowPNGForm2(PNGFile:string; nTran: integer);
var
pt1, pt2 : TPoint;
sz : TSize;
bf : TBlendFunction;
begin

bitmap:=tgpbitmap.Create(PNGFile);
pt1 := Point(left,top);
pt2 := Point(0, 0);
sz.cx := bitmap.GetWidth; sz.cy := bitmap.GetHeight;
bf.BlendOp := AC_SRC_OVER; bf.BlendFlags := 0;
if (nTran<0) or (nTran>255) then nTran:=255;
bf.SourceConstantAlpha := nTran;
bf.AlphaFormat := AC_SRC_ALPHA;
DeleteObject(bmp);
bitmap.GetHBITMAP(0,bmp); DeleteDC(DC);
DC := CreateCompatibleDC(Canvas.Handle);
old_bmp := SelectObject(DC, bmp);
UpdateLayeredWindow(Handle, Canvas.Handle, @pt1, @sz, DC, @pt2,0, @bf,ULW_ALPHA);
end;
 
没人知道啊 ?
 
我找到的例子似乎跟你的不一样,等我找到之后给你一份,你能发一份你的给我么? cnlohmann @ yeah.net

有个aquasoft网站里有零星的资料,他们做的界面类似Mac,很漂亮的,据说收到过苹果的律师函,所以网站现在不是很活跃
 
可以啊!我的lovezypj@sina.com!我找了类似的都是可以实现不规则窗体,但是控件全都不显示
 
这个问题一年前我就提问过,没人会。有个叫做 小雨哥 的人说要在鼠标点的时候在那个位置画个控件模样的东西,等等,反正我没听懂,他好像也不会。
 
你到检索里找找.
 
终于明白了,使用UpdateLayeredWindow后窗体就不会执行onpaint,小雨哥的也没解决!
总之,使用这个函数后把窗体当作静态图片处理了,没有onpaint事件,控件不会重画,也就不会显示,有些人说做两个窗体,然后重叠,但是这样程序体积要变大,处理也麻烦,超级兔子桌面秀是delphi7写的,同样使用了GDI+PNG做的窗体,不知道他怎么实现控件显示的
 
有个叫做“鱼鱼桌面秀”的软件里面使用了大量的PNG图片做界面,做得还很漂亮。我曾经跟作者问过怎么做的,他不愿意说,然后说是花钱买的技术,是一些dll文件弄的,做起来也挺麻烦的他说。
 
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,点按钮后后面的图片窗口不见了,大家帮忙改善一下!:)
 
这个问题看来要用另外的思路,不讨论了
 
后退
顶部