delphi(XE2)实现图片异形窗体,支持摆放控件

news/2025/2/11 12:05:11/

网上有较多使用UpdateLayeredWindow函数实现美化的图片异形窗体的代码,一般使用此场景时,对软件界面要求较高。但是实现了图片窗体后,在窗体中摆放不了其他控件,导致这个功能很鸡肋。为解决此问题,本博文中的案例使用两个窗体搭配使用,即图片窗口作为背景窗体,放置控件的窗口作为功能性窗体,功能性窗口全透明展示,就可实现我们预设的目标,效果如下:

 蓝色的圆球是一个png格式背景图片,没有直接用画布画圆,所以不会失真。实现本功能的主要关键点在于:

1、实现异形的背景窗口

2、功能性窗口除控件部分需全透明展示

3、支持鼠标移动窗体,且两个窗口要同步位移

4、两个窗口需要以相同顺序展示在屏幕最上方

下面贴主要代码段:

{*******************************************************}
{                                                       }
{       异形窗口                                        }
{       负责美观的背景窗口                                                }
{       版权所有 (C) 2022 云露软件                      }
{                                                       }
{*******************************************************}unit uBackground;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, acPNG, Vcl.ExtCtrls, Vcl.StdCtrls;typeTfrmBk = class(TForm)img1: TImage;procedure FormShow(Sender: TObject);procedure img1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);procedure img1MouseEnter(Sender: TObject);procedure img1MouseLeave(Sender: TObject);procedure img1Click(Sender: TObject);private{ Private declarations }procedure CreateParams(var Params: TCreateParams); override;procedure WMMove(var Message: TMessage) ; message WM_MOVE;//响应窗体移动的消息procedure WndProc(var Message: TMessage); override;public{ Public declarations }class procedure ShowFrm;end;varfrmBk: TfrmBk;implementationuses uMain;{$R *.dfm}
procedure YXForm_FromGraphic(AForm : TForm; AGraphic : TGraphic);
varptDst, ptSrc: TPoint;Size: TSize;BlendFunction: TBlendFunction;bmp : TBitmap;
beginbmp := TBitmap.Create;bmp.Assign(AGraphic);ptDst := Point(AForm.Left, AForm.Top);ptSrc := Point(0, 0);Size.cx := AGraphic.Width;Size.cy := AGraphic.Height;BlendFunction.BlendOp := AC_SRC_OVER;BlendFunction.BlendFlags := 0;BlendFunction.SourceConstantAlpha := $FF; // 透明度BlendFunction.AlphaFormat := AC_SRC_ALPHA;SetWindowLong(AForm.Handle, GWL_EXSTYLE, GetWindowLong(AForm.Handle,GWL_EXSTYLE) or WS_EX_LAYERED);UpdateLayeredWindow(AForm.Handle,AForm.Canvas.Handle,@ptDst,@Size,bmp.Canvas.Handle,@ptSrc,0,@BlendFunction,ULW_ALPHA);bmp.Free();
end;//根据png图片更换窗体样式:
procedure RefrashFormByPng(AForm: TForm;aFileName: string);
varwic: TWICImage;
beginwic := TWICImage.Create;trywic.LoadFromFile(aFileName);YXForm_FromGraphic(frmBk, wic);finallyFreeAndNil(wic);end;
end;procedure TfrmBk.CreateParams(var Params: TCreateParams);
begininherited;Params.WndParent := GetDesktopWindow ;//父窗口句柄设置为桌面Params.ExStyle := Params.ExStyle or WS_EX_TOOLWINDOW; //取消窗体在任务栏的图标
end;procedure TfrmBk.FormShow(Sender: TObject);
begin//同步控件窗体展示的大小、位置frmMain.Width := Self.Width;frmMain.Height := Self.Height;frmMain.Left := frmBk.Left-2;frmMain.Top := frmBk.Top-5;//置顶现实SetWindowPos(Handle, HWND_TOPMOST , 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);PostMessage(frmMain.Handle, WM_USER + 200, 0 , 0);
end;procedure TfrmBk.img1Click(Sender: TObject);
beginif not frmMain.Showing then//如果当前展示的是退出登录ModalResult := mrNo;
end;procedure TfrmBk.img1MouseEnter(Sender: TObject);
begin//鼠标点上去更换背景图,使用下面两句:RefrashFormByPng(frmBk,'退出.png');frmMain.Hide;//如果鼠标点上去仍然需要展示控件窗口,则使用下面这句:
//  SetWindowPos(Handle,HWND_NOTOPMOST,Left,Top,Width,Height,SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;procedure TfrmBk.img1MouseLeave(Sender: TObject);
begin//鼠标点上去更换背景图,使用下面两句:RefrashFormByPng(frmBk,'bk.png');SetWindowPos(Handle,HWND_TOPMOST,Left,Top,Width,Height,SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);//如果鼠标点上去仍然需要展示控件窗口,则使用下面这句:PostMessage(frmMain.Handle, WM_USER + 200, 0 , 0);
end;procedure TfrmBk.img1MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
begin//鼠标拖动窗体移动:if ssLeft in Shift thenReleaseCapture;Perform(WM_SYSCOMMAND, $F012, 0);
end;class procedure TfrmBk.ShowFrm;
beginfrmBk := TfrmBk.Create(Application);tryRefrashFormByPng(frmBk,'D:\HX_Code\bk.png');frmMain := TfrmMain.Create(Application);frmBk.ShowModal;finallyFreeAndNil(frmBk);//不要也行,Application释放时会自动释放end;
end;procedure TfrmBk.WMMove(var Message: TMessage);
beginif Assigned(frmMain) thenbegin//同步控件窗体展示的大小、位置frmMain.Left := frmBk.Left-2;frmMain.Top := frmBk.Top- 2;//如果鼠标点上去仍然需要展示控件窗口,则使用下面这句:
//    PostMessage(frmMain.Handle, WM_USER + 200, 0 , 0);end;
end;procedure TfrmBk.WndProc(var Message: TMessage);
begininherited WndProc(Message);if (not Application.MainFormOnTaskBar) and (Message.Msg = WM_SHOWWINDOW) thenbegin//取消任务栏现实ShowWindow(Application.Handle, SW_HIDE);SetWindowLong(Application.Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);end;
end;end.
{*******************************************************}
{                                                       }
{       功能窗口                                        }
{       主要摆放控件,实现一些业务逻辑                  }
{       版权所有 (C) 2022 云露软件                      }
{                                                       }
{*******************************************************}unit uMain;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, cxGraphics, cxControls,cxLookAndFeels, cxLookAndFeelPainters, cxContainer, cxEdit, cxLabel,Vcl.ExtCtrls;typeTfrmMain = class(TForm)cxLabel1: TcxLabel;tmr1: TTimer;procedure FormCreate(Sender: TObject);procedure tmr1Timer(Sender: TObject);procedure FormShow(Sender: TObject);private{ Private declarations }i: Integer;procedure WMSHOW(var Msg: TMessage); message WM_USER + 200;procedure CreateParams(var Params: TCreateParams); override;public{ Public declarations }end;varfrmMain: TfrmMain;implementationuses uBackground;
{$R *.dfm}procedure TfrmMain.CreateParams(var Params: TCreateParams);
begininherited;Params.WndParent := GetDesktopWindow ;//父窗口设为桌面,不会被其他窗口遮挡Params.ExStyle := Params.ExStyle or WS_EX_TOOLWINDOW; //取消窗体在任务栏的图标
end;procedure TfrmMain.FormCreate(Sender: TObject);
varmStyle, mExStyle: Longint;
begin//设置窗体为无标题mStyle:= GetWindowLong(Handle, GWL_STYLE);SetWindowLong(Handle, GWL_STYLE, mStyle and not WS_CAPTION);//设置窗体上指定颜色为全透明mExStyle:= GetWindowLong(Handle, GWL_EXSTYLE);SetWindowLong(Handle, GWL_EXSTYLE, mExStyle or WS_EX_LAYERED);SetLayeredWindowAttributes(Handle, Self.Color, 200, LWA_COLORKEY);i := 1;
end;procedure TfrmMain.FormShow(Sender: TObject);
beginSetWindowPos(frmMain.Handle, HWND_TOPMOST , 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
end;procedure TfrmMain.tmr1Timer(Sender: TObject);
begininc(i);cxLabel1.Caption :=  IntToStr(I)+'S';
end;procedure TfrmMain.WMSHOW(var Msg: TMessage);
beginSelf.Show;
end;end.

功能性窗口只有一个lable,为了让它的全透明效果更好,设置了lable居中显示,颜色为灰色(这个可以调整)。

//工程文件
program Project2;usesVcl.Forms,uBackground in 'uBackground.pas' {frmBk},uMain in 'uMain.pas' {frmMain};{$R *.res}beginApplication.Initialize;Application.MainFormOnTaskbar := False;TfrmBk.ShowFrm;Application.Run;
end.


http://www.ppmy.cn/news/496415.html

相关文章

XXE漏洞

XXE漏洞 1.漏洞简介 ​ XXE 漏洞全称XML External Entity Injection,即 XML 外部实体注入漏洞,XXE 漏洞发生在应用程序解析 XML 输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网…

Delphi XE2控件安装方法

1) 首先打开所需要安装控件的安装文件,点击open project... (有些非可视的老控件直接打开DPK文件即可) 2) 以安装DCPcrypt为例,打开控件工程后,在project manager中如下图所示。 3) 如图所示打开工程处单击鼠标右键,点击"INS…

Delphi XE2 发布了

报名参加了芝加哥的8月底发布会,到时候再给大家汇报情况。

Delphi.XE2破解方法

Delphi.XE2破解方法 我安装的是Delphi.XE2.RTM.v16.0.4256.43595.Lite.v5.0 ,安装完后打开显示是15天试用。 退出XE2后把C:\Program Files\Embarcadero\RAD Studio\9.0\License 文件夹删除。 再打开XE2就会出现注册窗口,如下图: 把Registrati…

C++Builder/Delphi XE2 UniDAC安装教程

CBuilder/Delphi XE2 UniDAC安装教程 UniDAC是一个功能强大的非可视化跨数据库的数据访问组件,可用于Delphi,Delphi for .NET,CBuilder,and Lazarus (Free Pascal)。它提供了对流行数据库服务器的统一访问,像Oracle&…

python复制文件路径时报错显示\xe2\x80\xaaE

今天下午,w 耗费了一下午的时间来解决这个报错问题!把我直接整 乌鸡鲅鱼! 百度方法1:路径改为手动输入。效果:成功,但是后面依旧失败。 学长方法2:不要绝对路径,改为相对路径。效果&…

XE2 和D7 的对比:

string 将会默认为 widestring 而在D7 中string 是ansistring char 认为 widechar; XE2有三种字符串:ansistring,widestring,UnicodeString (新增) XE2 多了一个UicodeString d7 TTypeKind (tkUnknown…

delphi XE2自带的皮肤控件

delphi XE2自带了皮肤控件,可以根据每个项目的需要开启,开启的方法:打开项目设置,如下图: 开启后,设计期的控件无任何变化,运行中可见,如下图: 再也不用自已安装第三方皮肤控件&…