如何在Windows 10系统中实现边角完美平滑的Delphi圆形窗体?
实现Windows 10下边角完全平滑的Delphi圆形窗体
嘿,我懂你纠结的点——用CreateRoundRectRgn做的圆形窗体边缘总有锯齿感,哪怕没加背景图也不够顺滑。这是因为传统GDI区域是硬边缘切割,没有抗锯齿处理,在Windows 10的高DPI环境下更明显。下面给你几个实用的方案,亲测有效:
方案1:用GDI+自绘抗锯齿圆形窗体
这是最可控的方法,能实现真正的平滑边缘,步骤如下:
- 首先在窗体的
private部分声明GDI+相关变量:
var FGDIPlusToken: TGDIPlusToken;
- 在窗体的
OnCreate事件里初始化GDI+,并设置窗体样式:
procedure TForm1.FormCreate(Sender: TObject); begin // 初始化GDI+ FGDIPlusToken := TGDIPlusToken.Create; // 去掉窗体边框 BorderStyle := bsNone; // 设置为分层窗口(支持透明和抗锯齿) SetWindowLongPtr(Handle, GWL_EXSTYLE, GetWindowLongPtr(Handle, GWL_EXSTYLE) or WS_EX_LAYERED); // 开启双缓冲 DoubleBuffered := True; end;
- 在窗体的
OnPaint事件里绘制平滑的圆形背景:
procedure TForm1.FormPaint(Sender: TObject); var Graphics: TGPGraphics; Brush: TGPBrush; R: TGPRectF; begin Graphics := TGPGraphics.Create(Canvas.Handle); try // 设置高质量抗锯齿 Graphics.SetSmoothingMode(SmoothingModeHighQuality); // 定义圆形区域(和窗体大小一致) R := MakeRect(0, 0, ClientWidth, ClientHeight); // 创建纯色画刷(替换成你需要的背景色) Brush := TGPPen.Create(TGPColor.Create(255, 240, 240, 240)); // 浅灰色示例 try // 绘制圆形边框 Graphics.DrawEllipse(Brush, R); // 填充圆形内部 Graphics.FillEllipse(TGPSolidBrush.Create(TGPColor.Create(255, 255, 255, 255)), R); finally Brush.Free; end; finally Graphics.Free; end; end;
- 在窗体的
OnDestroy事件里释放GDI+资源:
procedure TForm1.FormDestroy(Sender: TObject); begin FGDIPlusToken.Free; end;
方案2:利用Windows 10原生DWM圆角(仅Win10 1903+)
如果你的目标系统是Windows 10 1903及以上版本,可以直接调用系统的DWM API来实现原生平滑圆角,代码更简洁:
- 首先在单元里声明DWM相关常量和函数:
const DWMWA_WINDOW_CORNER_PREFERENCE = 33; type DWMWINDOWCORNERPREFERENCE = DWORD; const DWMWCP_DEFAULT = 0; DWMWCP_DONOTROUND = 1; DWMWCP_ROUND = 2; DWMWCP_ROUNDSMALL = 3; function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; const pvAttribute: Pointer; cbAttribute: DWORD): HRESULT; stdcall; external 'dwmapi.dll';
- 在窗体的
OnCreate事件里设置圆角:
procedure TForm1.FormCreate(Sender: TObject); var CornerPref: DWMWINDOWCORNERPREFERENCE; begin // 去掉窗体边框 BorderStyle := bsNone; // 设置为圆形需要的窗口大小(宽高一致) Width := 300; Height := 300; // 设置圆角偏好为完全圆形 CornerPref := DWMWCP_ROUND; DwmSetWindowAttribute(Handle, DWMWA_WINDOW_CORNER_PREFERENCE, @CornerPref, SizeOf(CornerPref)); end;
这个方法的优势是完全利用系统原生渲染,边缘平滑度和系统一致,而且不需要自己处理绘制。
方案3:优化传统Region方法(兼容旧系统)
如果你需要兼容更早的Windows版本,可以优化原来的Region方法,结合分层窗口和抗锯齿:
procedure TForm1.FormCreate(Sender: TObject); var HRgn: HRGN; begin // 隐藏主窗口,设置工具窗口样式 ShowWindow(Application.Handle, SW_HIDE); SetWindowLongPtr(Application.Handle, GWL_EXSTYLE, GetWindowLongPtr(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW); ShowWindow(Application.Handle, SW_SHOW); // 创建椭圆区域(真正的圆形,宽高要一致) HRgn := CreateEllipticRgn(0, 0, Width, Height); try // 设置窗口区域 SetWindowRgn(Handle, HRgn, True); // 设置分层窗口,启用抗锯齿 SetWindowLongPtr(Handle, GWL_EXSTYLE, GetWindowLongPtr(Handle, GWL_EXSTYLE) or WS_EX_LAYERED); SetLayeredWindowAttributes(Handle, 0, 255, LWA_ALPHA); finally // 这里不需要手动释放HRgn,SetWindowRgn会接管 end; end;
注意:这个方法的平滑度还是不如GDI+或DWM原生方法,但比你原来的代码要好,因为用了CreateEllipticRgn而不是CreateRoundRectRgn,并且启用了分层窗口。
额外注意事项
- 确保窗体的宽高一致,这样才能是正圆形,否则会变成椭圆形。
- 如果需要拖动窗体,可以在窗体的
OnMouseDown事件里处理WM_NCLBUTTONDOWN消息:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbLeft then Perform(WM_NCLBUTTONDOWN, HTCAPTION, 0); end;
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

