如何为PyQt5的QMenu设置Windows系统级柔和阴影而非默认阴影?
要实现VS Code、Spotify这类应用的系统级柔和阴影,你需要调用Windows原生API(Dwmapi)来为无框窗口启用系统阴影,而非依赖Qt自带的生硬阴影效果。以下是具体实现方案:
实现步骤
- 导入
ctypes模块调用Windows的DwmSetWindowAttribute函数,该函数用于配置桌面窗口管理器(DWM)的窗口属性 - 自定义
QMenu子类,重写showEvent方法,在菜单显示时为其添加系统阴影和匹配的圆角效果 - 移除原代码中的
NoDropShadowWindowHint标志,保留FramelessWindowHint和WA_TranslucentBackground属性以支持自定义样式
修改后的完整代码
import sys from PyQt5 import QtCore, QtWidgets import ctypes from ctypes import wintypes # 初始化Windows DWM API dwmapi = ctypes.WinDLL("dwmapi") # DWM属性常量 DWMWCP_ROUND = 2 # Windows 11圆角样式 DWMSWA_WINDOW_CORNER_PREFERENCE = 33 DWMSWA_MICA_EFFECT = 1029 # 可选,启用Windows 11云母效果 class CustomMenu(QtWidgets.QMenu): def showEvent(self, event): super().showEvent(event) # 获取菜单窗口句柄 hwnd = int(self.winId()) # 设置窗口圆角,匹配样式表中的border-radius corner_preference = wintypes.DWORD(DWMWCP_ROUND) dwmapi.DwmSetWindowAttribute( wintypes.HWND(hwnd), wintypes.DWORD(DWMSWA_WINDOW_CORNER_PREFERENCE), ctypes.byref(corner_preference), ctypes.sizeof(corner_preference) ) # 启用系统阴影(配合圆角自动生效) # 可选:启用云母效果增强视觉一致性 mica_enabled = wintypes.DWORD(1) dwmapi.DwmSetWindowAttribute( wintypes.HWND(hwnd), wintypes.DWORD(DWMSWA_MICA_EFFECT), ctypes.byref(mica_enabled), ctypes.sizeof(mica_enabled) ) def main(): app = QtWidgets.QApplication(sys.argv) win = QtWidgets.QMainWindow() app.setStyleSheet(''' QMenu { background: #2b2b2b; color: white; border-radius: 5px; border: 1px solid #3e3e3e; } QMenu::item { border-radius: 3px; padding: 4px 25px; margin: 2px 5px; } QMenu::item:selected { background: #353535; } ''') menubar = QtWidgets.QMenuBar() # 使用自定义菜单类替代默认QMenu settingsmenu = CustomMenu(menubar) settingsmenu.setTitle("Settings") settingsmenu.setWindowFlags(settingsmenu.windowFlags() | QtCore.Qt.FramelessWindowHint) # 移除NoDropShadowWindowHint,允许系统添加阴影 settingsmenu.setAttribute(QtCore.Qt.WA_TranslucentBackground) run_on_start = QtWidgets.QAction(text="Run On Startup", checkable=True) start_minimized = QtWidgets.QAction(text="Start Minimized", checkable=True) settingsmenu.addAction(run_on_start) settingsmenu.addAction(start_minimized) menubar.addAction(settingsmenu.menuAction()) win.setMenuBar(menubar) win.resize(400, 300) win.show() sys.exit(app.exec_()) if __name__ == "__main__": main()
注意事项
- 该方案仅支持Windows 10及以上系统,其中圆角和云母效果为Windows 11专属特性
- 确保样式表中的
border-radius与代码中设置的圆角样式匹配,避免视觉错位 - 若不需要云母效果,可注释掉对应
DwmSetWindowAttribute调用,仅保留圆角设置即可正常显示系统阴影
内容的提问来源于stack exchange,提问作者Itsjul1an
相关产品推荐
相关产品推荐

