You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

调用SetWindowCompositionAttribute实现亚克力效果时的窗口圆角方案问询

解决亚克力效果与圆角窗口兼容的问题

我之前也踩过这个坑!核心原因是亚克力效果是由DWM(桌面窗口管理器)直接渲染在窗口底层的SetWindowRgn只能裁剪窗口的客户区控件内容,根本碰不到DWM绘制的亚克力背景层,所以才会出现圆角遮不住亚克力的情况。下面给你几个经过实际验证的可行思路:

方案一:用系统原生DWM圆角API(推荐)

Windows 10 1809及以上版本提供了原生的圆角窗口支持,通过DwmSetWindowAttribute设置DWMWA_WINDOW_CORNER_PREFERENCE属性,就能让系统自动给窗口加圆角,而且亚克力效果会完美适配圆角裁剪,完全不用自己处理遮罩逻辑。

在PyQt中可以这么实现:

import win32api
import win32con
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
        self.resize(500, 500)
        
        # 调用DWM设置圆角
        hwnd = int(self.winId())
        # 定义需要的常量(如果win32con未包含)
        DWMWA_WINDOW_CORNER_PREFERENCE = 33
        DWMWCP_ROUND = 2  # 完全圆角,还有DWMWCP_ROUNDSMALL等选项
        
        # 先移除标题栏和边框(按需操作)
        current_style = win32api.GetWindowLongPtr(hwnd, win32con.GWL_STYLE)
        new_style = current_style & ~win32con.WS_CAPTION & ~win32con.WS_THICKFRAME
        win32api.SetWindowLongPtr(hwnd, win32con.GWL_STYLE, new_style)
        
        # 设置圆角偏好
        win32api.DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_ROUND, 4)

这个方案的优势是系统原生支持,适配高DPI、多显示器都很友好,而且代码量最少。

方案二:手动模拟亚克力+Qt遮罩(兼容旧系统)

如果需要兼容Windows 10 1809以下版本,或者要自定义圆角大小,可以放弃系统原生的亚克力,改用DwmEnableBlurBehindWindow实现模糊背景,再配合Qt的setMask做圆角裁剪,最后自己绘制半透明背景模拟亚克力质感:

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QPainter, QPainterPath, QRegion, QColor
from PyQt5.QtCore import Qt
import win32api
import win32con

class AcrylicRoundWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.resize(500, 500)
        
        # 启用窗口背景模糊
        hwnd = int(self.winId())
        class DWM_BLURBEHIND(win32api.Structure):
            _fields_ = [("dwFlags", win32con.DWORD),
                        ("fEnable", win32con.BOOL),
                        ("hRgnBlur", win32con.HRGN),
                        ("fTransitionOnMaximized", win32con.BOOL)]
        
        blur_behind = DWM_BLURBEHIND()
        blur_behind.dwFlags = 1  # DWM_BB_ENABLE
        blur_behind.fEnable = True
        blur_behind.hRgnBlur = 0
        win32api.DwmEnableBlurBehindWindow(hwnd, blur_behind)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # 创建圆角路径
        round_path = QPainterPath()
        round_path.addRoundedRect(self.rect(), 50, 50)  # 自定义圆角半径
        
        # 设置窗口遮罩,裁剪出圆角
        self.setMask(QRegion(round_path.toFillPolygon().toPolygon()))
        
        # 绘制半透明背景模拟亚克力效果
        painter.fillPath(round_path, QColor(240, 240, 245, 190))  # 颜色和透明度可调整

这个方案虽然需要自己处理背景绘制,但兼容性更好,而且圆角大小完全可控。

方案三:用Qt原生的亚克力支持(Qt 5.14+)

Qt 5.14及以上版本提供了Qt.WinAcrylicWindow窗口组合提示,结合WA_TranslucentBackgroundsetMask可以实现圆角亚克力窗口:

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QPainterPath, QRegion
from PyQt5.QtCore import Qt

class AcrylicRoundWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        # 启用Qt原生亚克力效果
        self.setWindowCompositionHint(Qt.WinAcrylicWindow)
        self.resize(500, 500)
        
        # 设置圆角遮罩
        round_path = QPainterPath()
        round_path.addRoundedRect(self.rect(), 50, 50)
        self.setMask(QRegion(round_path.toFillPolygon().toPolygon()))

注意:这个方法需要确保Qt版本符合要求,而且部分环境下可能需要调整窗口背景色来匹配亚克力的视觉效果。


内容的提问来源于stack exchange,提问作者zhiyi

火山引擎 最新活动