如何在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 文档中介绍了亚克力材料的配方, ...
随机推荐
- window11连接局域网共享失败处理办法
第一步1.按 Win + R 组合键,打开运行,并输入:gpedit.msc 命令,确定或回车,可以快速打开本地组策略编辑器2.本地组策略编辑器窗口中,依次展开到:计算机配置 - 管理模板 - 网络 ...
- 使用.NET 6开发TodoList应用(9)——实现PUT请求
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 PUT请求本身其实可说的并不多,过程也和创建基本类似.在这篇文章中,重点是填上之前文章里留的一个坑,我们曾经给TodoItem ...
- 理解HTTP协议中的multipart/form-data
前提 之前在写一个通用HTTP组件的时候遇到过媒体(Media)类型multipart/form-data的封装问题,这篇文章主要简单介绍一下HTTP协议中媒体类型multipart/form-dat ...
- C# 服务器发送邮件失败
邮件发送相关端口 首先说下邮件发送的端口:25/465/587 25端口 25端口是为SMTP协议服务开放的,是这三个端口中最老的一个.25端口也称为消息中继端口,因为这个端口经常被恶意利用,所以现在 ...
- Linux下如何部署FTP服务器
FTP 是 File Transfer Protocol 的缩写,即文件传输协议,它通过网络在服务器和客户端之间传输文件,现在已经成为一种广泛使用的标准工具 vsftpd 是 very secure ...
- 【Spring专场】「IOC容器」不看源码就带你认识核心流程以及运作原理
这是史上最全面的Spring的核心流程以及运作原理的分析指南 [Spring核心专题]「IOC容器篇」不看繁琐的源码就带你浏览Spring的核心流程以及运作原理 [Spring核心专题]「AOP容器篇 ...
- Python DataFrame to_sql方法插入日期或时间类型的数据时 报ORA-01861 文字与字符串不匹配 的解决方法
业务团队近期提出一个需求: 希望在接口调用之前先批量插入Excel中的数据作为数据预置 这个需求以前已经开发完成 本来以为可以很快调试完毕 没成想遭遇一个难关 DataFrame.to_sql方法在执 ...
- VirtualBox 虚拟机怎样设置共享文件夹
首次在VirtualBox装完系统后,很经常用到的操作就是:想将主机的东西拉倒虚拟机进行使用或安装,那怎么将主机的文件拿到虚拟机呢? 1.在虚拟机 > 设置中选择 >安装增强功能,经过这个 ...
- NIO【同步非阻塞io模型】关于 文件io 的总结
1.前言 这一篇随笔是写 NIO 关于文件输入输出的总结 /* 总结: 1.io操作包括 socket io ,file io ; 2.在nio模型,file io使用fileChannel 管道 , ...
- 计算机视觉--CV技术指南文章汇总
前言 本文汇总了过去本公众号原创的.国外博客翻译的.从其它公众号转载的.从知乎转载的等一些比较重要的文章,并按照论文分享.技术总结三个方面进行了一个简单分类.点击每篇文章标题可阅读详细内容 欢迎关注 ...