如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果
亚克力效果
在《如何在pyqt中实现窗口磨砂效果》和《如何在pyqt中实现win10亚克力效果》中,我们调用C++ dll来实现窗口效果,这种方法要求电脑上必须装有MSVC。Visual Studio装起来确实费时又占C盘空间,所以今天在python中直接调用 SetWindowCompositionAttribute,关于更多无边框窗体的解决方案可以参见《如何在pyqt中自定义无边框窗口》。下面是这次的亚克力效果(硝子太美了(๑¯∀¯๑)):

具体代码
结构体和枚举类
为了调用 Windows 的 API,我们需要定义一些结构体和枚举类,具体如下:
# coding:utf-8
from ctypes import POINTER, Structure
from ctypes.wintypes import DWORD, HWND, ULONG
from enum import Enum
class WINDOWCOMPOSITIONATTRIB(Enum):
    WCA_UNDEFINED = 0,
    WCA_NCRENDERING_ENABLED = 1,
    WCA_NCRENDERING_POLICY = 2,
    WCA_TRANSITIONS_FORCEDISABLED = 3,
    WCA_ALLOW_NCPAINT = 4,
    WCA_CAPTION_BUTTON_BOUNDS = 5,
    WCA_NONCLIENT_RTL_LAYOUT = 6,
    WCA_FORCE_ICONIC_REPRESENTATION = 7,
    WCA_EXTENDED_FRAME_BOUNDS = 8,
    WCA_HAS_ICONIC_BITMAP = 9,
    WCA_THEME_ATTRIBUTES = 10,
    WCA_NCRENDERING_EXILED = 11,
    WCA_NCADORNMENTINFO = 12,
    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
    WCA_VIDEO_OVERLAY_ACTIVE = 14,
    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
    WCA_DISALLOW_PEEK = 16,
    WCA_CLOAK = 17,
    WCA_CLOAKED = 18,
    WCA_ACCENT_POLICY = 19,
    WCA_FREEZE_REPRESENTATION = 20,
    WCA_EVER_UNCLOAKED = 21,
    WCA_VISUAL_OWNER = 22,
    WCA_LAST = 23
class ACCENT_STATE(Enum):
    """ 客户区状态枚举类 """
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_GRADIENT = 1,
    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
    ACCENT_ENABLE_BLURBEHIND = 3,          # Aero效果
    ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,   # 亚克力效果
    ACCENT_INVALID_STATE = 5
class ACCENT_POLICY(Structure):
    """ 设置客户区的具体属性 """
    _fields_ = [
        ('AccentState',   DWORD),
        ('AccentFlags',   DWORD),
        ('GradientColor', DWORD),
        ('AnimationId',   DWORD),
    ]
class WINDOWCOMPOSITIONATTRIBDATA(Structure):
    _fields_ = [
        ('Attribute',  DWORD),
        ('Data',       POINTER(ACCENT_POLICY)), # POINTER()接收任何ctypes类型,并返回一个指针类型
        ('SizeOfData', ULONG),
    ]
WindowEffect 类
WindowEffect 的 setAcrylicEffect 函数中新增了两个参数—— isEnableShadow 和 animationId,一个控制亚克力窗口的阴影,另一个控制磨砂动画。在demo中是看不出 animationId 的具体效果的,只有窗口最大化和还原时这个动画过程才会显现出来,具体过程可以参见上一篇博客,里面的动图显示得很清楚,下面是这个类的代码:
# coding:utf-8
from ctypes import POINTER, c_bool, sizeof, windll,pointer,c_int
from ctypes.wintypes import DWORD, HWND, ULONG
from win32 import win32api, win32gui
from win32.lib import win32con
from .c_structures import (ACCENT_POLICY, ACCENT_STATE,
                        WINDOWCOMPOSITIONATTRIB,
                        WINDOWCOMPOSITIONATTRIBDATA)
class WindowEffect():
    """ 调用windows api实现窗口效果 """
    def __init__(self):
        # 调用api
        self.SetWindowCompositionAttribute = windll.user32.SetWindowCompositionAttribute
        self.SetWindowCompositionAttribute.restype = c_bool
        self.SetWindowCompositionAttribute.argtypes = [
            c_int, POINTER(WINDOWCOMPOSITIONATTRIBDATA)]
        # 初始化结构体
        self.accentPolicy = ACCENT_POLICY()
        self.winCompAttrData = WINDOWCOMPOSITIONATTRIBDATA()
        self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value[0]
        self.winCompAttrData.SizeOfData = sizeof(self.accentPolicy)
        self.winCompAttrData.Data = pointer(self.accentPolicy)
    def setAcrylicEffect(self, hWnd: int, gradientColor: str = 'F2F2F230',
                         isEnableShadow: bool = True, animationId: int = 0):
        """ 开启亚克力效果
        Parameters
        ----------
        hWnd: int
            窗口句柄
        gradientColor: str
             十六进制亚克力混合色,对应 RGBA 四个分量
        isEnableShadow: bool
            是否启用窗口阴影
        animationId: int
            控制磨砂动画
        """
        # 亚克力混合色
        gradientColor = gradientColor[6:] + gradientColor[4:6] + \
            gradientColor[2:4] + gradientColor[:2]
        gradientColor = DWORD(int(gradientColor, base=16))
        # 磨砂动画
        animationId = DWORD(animationId)
        # 窗口阴影
        accentFlags = DWORD(0x20 | 0x40 | 0x80 |
                            0x100) if isEnableShadow else DWORD(0)
        self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_ACRYLICBLURBEHIND.value[0]
        self.accentPolicy.GradientColor = gradientColor
        self.accentPolicy.AccentFlags = accentFlags
        self.accentPolicy.AnimationId = animationId
        # 开启亚克力
        self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
    def setAeroEffect(self, hWnd: int):
        """ 开启 Aero 效果
        Parameter
        ----------
        hWnd: int
            窗口句柄
        """
        self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND.value[0]
        # 开启Aero
        self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
    def moveWindow(self, hWnd: int):
        """ 移动窗口
        Parameter
        ----------
        hWnd: int or `sip.voidptr`
            窗口句柄
        """
        win32gui.ReleaseCapture()
        win32api.SendMessage(hWnd, win32con.WM_SYSCOMMAND,
                    win32con.SC_MOVE + win32con.HTCAPTION, 0)
demo
# coding:utf-8
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget
from my_window_effect import WindowEffect
class Demo(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.windowEffect = WindowEffect()
        self.resize(500, 500)
        self.setWindowFlags(Qt.FramelessWindowHint)
        # 必须用样式表使背景透明,别用 setAttribute(Qt.WA_TranslucentBackground),不然界面会卡顿
        self.setStyleSheet("background:transparent")
        self.windowEffect.setAcrylicEffect(int(self.winId()))
    def mousePressEvent(self, QMouseEvent):
        """ 移动窗口 """
        self.windowEffect.moveWindow(self.winId())
if __name__ == "__main__":
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())
写在最后
文中用到的文件我都放在了百度网盘(提取码:m1jr)中,可以自取,喜欢的话就点个赞吧~~
如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果的更多相关文章
- 如何在pyqt中自定义无边框窗口
		前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ... 
- 如何在pyqt中实现窗口磨砂效果
		磨砂效果的实现思路 这两周一直在思考怎么在pyqt上实现窗口磨砂效果,网上搜了一圈,全都是 C++ 的实现方法.正好今天查python的官方文档的时候看到了 ctypes 里面的 HWND,想想倒不如 ... 
- 如何在pyqt中实现win10亚克力效果
		亚克力效果的实现思路 上一篇博客<如何在pyqt中实现窗口磨砂效果> 中实现了win7中的Aero效果,但是和win10的亚克力效果相比,Aero还是差了点内味.所以今天早上又在网上搜了一 ... 
- 如何在pyqt中给无边框窗口添加DWM环绕阴影
		前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ... 
- 如何在pyqt中实现带动画的动态QMenu
		弹出菜单的视觉效果 QLineEdit 原生的菜单弹出效果十分生硬,而且样式很丑.所以照着Groove中单行输入框弹出菜单的样式和动画效果写了一个可以实现动态变化Item的弹出菜单,根据剪贴板的内容是 ... 
- 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)
		无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ... 
- 如何在 pyqt 中捕获并处理 Alt+F4 快捷键
		前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ... 
- 如何在pyqt中使用 QGraphicsView 实现图片查看器
		前言 在 PyQt 中可以使用很多方式实现照片查看器,最朴素的做法就是重写 QWidget 的 paintEvent().mouseMoveEvent 等事件,但是如果要在图像上多添加一些形状,那么在 ... 
- 如何在pyqt中实现亚克力磨砂效果的QLabel
		前言 Windows10 在 UWP 应用中支持亚克力画刷,可以在部件的底部绘制亚克力效果的背景图.下面我们使用 QLabel 来模拟这个磨砂过程. 实现方法 MSDN 文档中介绍了亚克力材料的配方, ... 
随机推荐
- WPF中的StaticResource和DynamicResource有什么区别
			StaticResource 是静态资源 DynamicResource是动态资源 用一下例子说明 <Window.Resources> <Style x:Key="Bor ... 
- a.equals(b) 判断对象相等
			一.值是null的情况: 1.a.equals(b), a 是null, 抛出NullPointException异常. 2.a.equals(b), a不是null, b是null, 返回fals ... 
- 第三十四个知识点:描述攻击离散对数问题的baby-step/Giant-step方法
			第三十四个知识点:描述攻击离散对数问题的baby-step/Giant-step方法 Baby-step/Giant-step是Dnaiel Shanks为解决DLP问题开发的算法.DLP问题已经是许 ... 
- Linux Cgroups详解(一)
			[转载]http://blog.chinaunix.net/uid-23253303-id-3999432.html Cgroups是什么? Cgroups是control groups的缩写,是Li ... 
- JPEG原理详解 (转载)
			JPEG算法解密 by jinchao 图片压缩有多重要,可能很多人可能并没有一个直观上的认识,举个例子,一张800X800大小的普通图片,如果未经压缩,大概在1.7MB左右,这个体积如果存放文本 ... 
- Salesforce LWC学习(三十八) lwc下如何更新超过1万的数据
			背景: 今天项目组小伙伴问了一个问题,如果更新数据超过1万条的情况下,有什么好的方式来实现呢?我们都知道一个transaction只能做10000条DML数据操作,那客户的操作的数据就是超过10000 ... 
- 使用pynput同时监听鼠标和键盘
			pynput概述 pynput是一个基于python的,能够监听和控制鼠标和键盘的第三方库. pynput主要包括两个类,pynput.mouse和pynput.keyboard,顾名思义,前者可以用 ... 
- [JNI开发]使用javah命令生成.h的头文件
			第一步:进入对应的.java目录 javac xxx.java 生成对应的xxx.class文件 第二步:退回到/java目录 javah -classpath . -jni 包名.类名 
- CS5268 Typec转HDMI+VGA+PD3.0四合一扩展坞转换器方案芯片
			Capstone CS5268AN是一款高性能Type-C/DP1.4至HDMI2.0b和VGA转换器,设计用于将USB Type-C源或DP1.4源连接至HDMI2.0b接收器.CS5268AN集成 ... 
- 单芯片替代PS176 DP转HDMI 4K60HZ DP转HDMI2.0转换芯片CS5263
			PS176是一个显示端口 (DP)至HDMI 2.0视频接口转换器适用于需要视频协议转换的电缆适配器.电视接收器.监视器和其他应用.它将接受任何显示端口输入格式,包括DP 1.1a.dp1.2a.dp ... 
