You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Windows 10系统中实现边角完美平滑的Delphi圆形窗体?

实现Windows 10下边角完全平滑的Delphi圆形窗体

嘿,我懂你纠结的点——用CreateRoundRectRgn做的圆形窗体边缘总有锯齿感,哪怕没加背景图也不够顺滑。这是因为传统GDI区域是硬边缘切割,没有抗锯齿处理,在Windows 10的高DPI环境下更明显。下面给你几个实用的方案,亲测有效:

方案1:用GDI+自绘抗锯齿圆形窗体

这是最可控的方法,能实现真正的平滑边缘,步骤如下:

  1. 首先在窗体的private部分声明GDI+相关变量:
var
  FGDIPlusToken: TGDIPlusToken;
  1. 在窗体的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;
  1. 在窗体的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;
  1. 在窗体的OnDestroy事件里释放GDI+资源:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FGDIPlusToken.Free;
end;

方案2:利用Windows 10原生DWM圆角(仅Win10 1903+)

如果你的目标系统是Windows 10 1903及以上版本,可以直接调用系统的DWM API来实现原生平滑圆角,代码更简洁:

  1. 首先在单元里声明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';
  1. 在窗体的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:57:51