如何为自定义BorderStyle的FireMonkey窗体添加Windows原生阴影?
解决FireMonkey自定义BorderStyle窗体的原生Windows阴影问题
针对自定义BorderStyle后丢失Windows原生阴影的问题,以下是几种可行的解决方案:
方法1:调用DWM API启用原生阴影
FireMonkey默认窗体的阴影依赖Windows桌面窗口管理器(DWM)渲染,自定义边框时FMX会关闭相关DWM支持,需手动开启:
- 声明DWM相关函数与常量
在窗体单元的interface部分添加:
uses Windows; type TDWMWINDOWATTRIBUTE = DWORD; const DWMWA_NCRENDERING_POLICY = 2; DWMWA_WINDOW_CORNER_PREFERENCE = 33; DWMNCRP_ENABLED = 2; DWMWCP_DEFAULT = 0; function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: TDWMWINDOWATTRIBUTE; const pvAttribute: Pointer; cbAttribute: DWORD): HRESULT; stdcall; external 'dwmapi.dll' name 'DwmSetWindowAttribute'; function DwmIsCompositionEnabled(out pfEnabled: BOOL): HRESULT; stdcall; external 'dwmapi.dll' name 'DwmIsCompositionEnabled';
- 在窗体创建时启用DWM阴影
在窗体的OnCreate事件中添加代码:
procedure TMainForm.FormCreate(Sender: TObject); var DwmEnabled: BOOL; Policy: DWORD; begin // 检查DWM是否启用 if Succeeded(DwmIsCompositionEnabled(DwmEnabled)) and DwmEnabled then begin // 启用非客户区渲染,让DWM绘制阴影 Policy := DWMNCRP_ENABLED; DwmSetWindowAttribute(Handle, DWMWA_NCRENDERING_POLICY, @Policy, SizeOf(Policy)); // 设置窗口角落为系统默认,确保阴影样式匹配系统 Policy := DWMWCP_DEFAULT; DwmSetWindowAttribute(Handle, DWMWA_WINDOW_CORNER_PREFERENCE, @Policy, SizeOf(Policy)); // 添加WS_EX_APPWINDOW扩展样式,避免系统忽略阴影 SetWindowLongPtr(Handle, GWL_EXSTYLE, GetWindowLongPtr(Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW); // 强制窗口刷新非客户区 Perform(WM_NCCALCSIZE, 0, 0); end; end;
方法2:调整样式Mask区域显示TShadowEffect(模拟阴影)
如果原生DWM方案不适用,可修正TShadowEffect的显示问题:
- 打开Style Designer,找到窗体的
Mask组件(通常是TRectangle) - 将
Mask的Width和Height分别扩大10-15像素(上下左右各留阴影空间) - 确保
TShadowEffect的OffsetX、OffsetY和BlurRadius设置合理,此时阴影会被包含在Mask范围内正常显示
注意事项
- 不要使用
CS_DROPSHADOW,这是GDI时代的旧阴影效果,仅能生成小型阴影,并非Windows原生的DWM阴影 - 自定义BorderStyle时,需确保窗体
BorderStyle设置为bsNone,通过WindowBorderStyle处理非客户区逻辑
内容的提问来源于stack exchange,提问作者JvA
相关产品推荐
相关产品推荐

