您始终可以在表单上创建表单。这不是最快乐的解决方案,但它有效。我相信解决这个问题的最好方法是使用 GDI+ 或 D2D,但不幸的是,我无法弄清楚,所以我采用了“form on form”的方法:
分层形式:
unit uLayeredForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, System.Types,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.PngImage;
type
TfrmLayered = class(TForm)
procedure FormActivate(Sender: TObject);
private
FParentForm: TForm;
procedure SetAlphaBackground(const AResourceName: String);
public
constructor Create(AOwner: TComponent; const ABitmapResourceName: String); reintroduce;
procedure UpdatePosition;
end;
var
frmLayered: TfrmLayered;
implementation
{$R *.dfm}
constructor TfrmLayered.Create(AOwner: TComponent; const ABitmapResourceName: String);
begin
inherited Create(AOwner);
FParentForm := AOwner as TForm;
SetAlphaBackground(ABitmapResourceName);
end;
procedure TfrmLayered.FormActivate(Sender: TObject);
begin
if (Active) and (FParentForm.Visible) and (Assigned(FParentForm)) then
FParentForm.SetFocus;
end;
procedure TfrmLayered.UpdatePosition;
begin
if Assigned(FParentForm) then
begin
Left := FParentForm.Left - (ClientWidth - FParentForm.ClientWidth) div 2 - 1;
Top := FParentForm.Top - (ClientHeight - FParentForm.ClientHeight) div 2 - 1;
end;
end;
procedure TfrmLayered.SetAlphaBackground(const AResourceName: String);
var
blend_func: TBlendFunction;
imgpos : TPoint;
imgsize : TSize;
exStyle : DWORD;
png : TPngImage;
bmp : TBitmap;
begin
// enable window layering
exStyle := GetWindowLongA(Handle, GWL_EXSTYLE);
if ((exStyle and WS_EX_LAYERED) = 0) then
SetWindowLong(Handle, GWL_EXSTYLE, exStyle or WS_EX_LAYERED);
png := TPngImage.Create;
try
png.LoadFromResourceName(HInstance, AResourceName);
bmp := TBitmap.Create;
try
bmp.Assign(png);
// resize the form
ClientWidth := bmp.Width;
ClientHeight := bmp.Height;
// position image on form
imgpos := Point(0, 0);
imgsize.cx := bmp.Width;
imgsize.cy := bmp.Height;
// setup alpha blending parameters
blend_func.BlendOp := AC_SRC_OVER;
blend_func.BlendFlags := 0;
blend_func.SourceConstantAlpha := 255;
blend_func.AlphaFormat := AC_SRC_ALPHA;
UpdateLayeredWindow(Handle, 0, nil, @imgsize, bmp.Canvas.Handle, @imgpos, 0, @blend_func, ULW_ALPHA);
finally
bmp.Free;
end;
finally
png.Free;
end;
end;
end.
主要形式:
unit uMainForm;
interface
uses
uLayeredForm,
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;
type
TfrmMain = class(TForm)
imgClose: TImage;
procedure FormCreate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure FormShow(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormHide(Sender: TObject);
procedure imgCloseClick(Sender: TObject);
private
FLayeredForm: TfrmLayered;
protected
procedure WMMove(var AMessage: TMessage); message WM_MOVE;
public
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
uses
uCommon, Vcl.Themes, Vcl.Styles.FormStyleHooks;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
{$IFDEF DEBUG} ReportMemoryLeaksOnShutdown := TRUE; {$ENDIF}
FLayeredForm := TfrmLayered.Create(self, 'MainBackground');
FLayeredForm.Visible := TRUE;
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
FLayeredForm.Free;
end;
procedure TfrmMain.FormHide(Sender: TObject);
begin
FLayeredForm.Hide;
end;
procedure TfrmMain.WMMove(var AMessage: TMessage);
begin
if Assigned(FLayeredForm) then
FLayeredForm.UpdatePosition;
inherited;
end;
procedure TfrmMain.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
FormMove(self, Button, Shift, X, Y);
end;
procedure TfrmMain.FormShow(Sender: TObject);
begin
if Assigned(FLayeredForm) then
begin
FLayeredForm.Show;
FLayeredForm.UpdatePosition;
end;
end;
procedure TfrmMain.imgCloseClick(Sender: TObject);
begin
Close;
end;
initialization
TStyleManager.Engine.RegisterStyleHook(TfrmMain, TFormStyleHookBackground);
TFormStyleHookBackground.BackGroundSettings.Color := clBlack;
TFormStyleHookBackground.BackGroundSettings.Enabled := TRUE;
end.
如您所见,您必须做一些手动工作才能使两个表单表现得像一个,但是这段代码应该可以帮助您入门。
由于我需要具有平滑圆形边框的表格,因此我得到了以下屏幕截图。我将顶部表格涂成灰色,特别是为了这篇文章,以便更容易区分它和分层黑色表格:
您可以清楚地看到带锯齿的灰色表单边框(由SetWindowRgn()和 CreateRoundRectRgn() API 制作)和抗锯齿黑色表单边框之间的区别。