如何在pyqt中实现带动画的动态QMenu
弹出菜单的视觉效果
QLineEdit 原生的菜单弹出效果十分生硬,而且样式很丑。所以照着Groove中单行输入框弹出菜单的样式和动画效果写了一个可以实现动态变化Item的弹出菜单,根据剪贴板的内容是否为文本、编辑框是否有文本以及是否有选中文本分为6种情况,大体效果如下所示(ヾ(๑╹◡╹)ノ" 硝子依旧如此迷人:

具体实现流程
Menu 类
Menu 继承自 QMenu,在这个类中通过调用自定义类 WindowEffect 的方法来调用win10的api从而实现Aero效果和阴影效果,定义WindowEffect的代码放在了文末的链接中,可以自取,而Aero效果的实现方法不妨先康康 《如何在pyqt中实现窗口磨砂效果》,需要指出的是要想实现这两种效果需要事先安装好 MSVC (不安装 MSVC 的解决方案参见 (《如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果》)。Menu 类的具体代码如下:
import sys
from ctypes.wintypes import HWND
from PyQt5.QtCore import QAbstractAnimation, QEasingCurve, QEvent, Qt, QPropertyAnimation, QRect
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QAction, QApplication, QGraphicsDropShadowEffect, QMenu
from window_effect import WindowEffect
class Menu(QMenu):
""" 自定义菜单 """
windowEffect = WindowEffect()
def __init__(self, string='', parent=None):
super().__init__(string,parent)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup | Qt.NoDropShadowWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground | Qt.WA_StyledBackground)
self.setQss()
def event(self, e: QEvent):
if e.type() == QEvent.WinIdChange:
self.hWnd = HWND(int(self.winId()))
self.setMenuEffect()
return QMenu.event(self, e)
def setMenuEffect(self):
""" 添加特效 """
self.windowEffect.setAeroEffect(self.hWnd)
self.windowEffect.addShadowEffect(True,self.hWnd)
def setQss(self):
""" 设置层叠样式 """
with open('menu.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
LineEditMenu 类
LineEditMenu 继承自 Menu,需要注意的是这个类对 parent 的是有要求的,具体要求见代码:
class LineEditMenu(Menu):
""" 单行输入框右击菜单 """
def __init__(self, parent):
super().__init__('', parent)
# 实例化动画,注意不能直接改width这个只读的属性
self.animation = QPropertyAnimation(self, b'geometry')
self.initWidget()
def initWidget(self):
""" 初始化小部件 """
self.setObjectName('lineEditMenu')
# 设置动画持续时间
self.animation.setDuration(300)
# 设置插值方式
self.animation.setEasingCurve(QEasingCurve.OutQuad)
def createActions(self):
# 创建动作
self.cutAct = QAction(
QIcon('images\\黑色剪刀.png'), '剪切', self, shortcut='Ctrl+X', triggered=self.parent().cut)
self.copyAct = QAction(
QIcon('images\\黑色复制.png'), '复制', self, shortcut='Ctrl+C', triggered=self.parent().copy)
self.pasteAct = QAction(
QIcon('images\\黑色粘贴.png'), '粘贴', self, shortcut='Ctrl+V', triggered=self.parent().paste)
self.cancelAct = QAction(
QIcon('images\\黑色撤销.png'), '取消操作', self, shortcut='Ctrl+Z', triggered=self.parent().undo)
self.selectAllAct = QAction('全选', self, shortcut='Ctrl+A', triggered=self.parent().selectAll)
# 创建动作列表
self.action_list = [self.cutAct, self.copyAct, self.pasteAct, self.cancelAct, self.selectAllAct]
def exec_(self, pos):
""" 重写exec_() """
# 删除所有动作
self.clear()
# clear会直接delete之前的动作故需重新创建
self.createActions()
# 初始化属性,本来是在没有添加动画时为qss设置的,设置动画之后这个属性没什么用
self.setProperty('hasCancelAct', 'false')
width = 176
# 本来是在后面调用columnCount()来计算item个数的,结果算出来是1,所以手动创建一个变量来记录Item个数
actionNum = len(self.action_list)
# 访问系统剪贴板
self.clipboard = QApplication.clipboard()
# 根据剪贴板内容是否为text分两种情况讨论
if self.clipboard.mimeData().hasText():
# 再根据3种情况分类讨论
if self.parent().text():
self.setProperty('hasCancelAct', 'true')
width = 213
if self.parent().selectedText():
self.addActions(self.action_list)
else:
self.addActions(self.action_list[2:])
actionNum -= 2
else:
self.addAction(self.pasteAct)
actionNum = 1
else:
if self.parent().text():
self.setProperty('hasCancelAct', 'true')
width = 213
if self.parent().selectedText():
self.addActions(self.action_list[:2] + self.action_list[3:])
actionNum -= 1
else:
self.addActions(self.action_list[3:])
actionNum -= 3
else:
return
# 每个item的高度为38px,10为上下的内边距和
height = actionNum * 38 + 10
# 不能把初始的宽度设置为0px,不然会报警
self.animation.setStartValue(
QRect(pos.x(), pos.y(), 1, height))
self.animation.setEndValue(
QRect(pos.x(), pos.y(), width, height))
self.setStyle(QApplication.style())
# 开始动画
self.animation.start()
super().exec_(pos)
源代码和dll
动图中用到的编辑框是可以实现对音频文件标签信息的写入的,具体实现方法放在了我的github仓库中,喜欢的话可以给我点个小星星,下面是这次用到的代码、dll以及资源文件的网盘链接(提取码:fl4m):链接
如何在pyqt中实现带动画的动态QMenu的更多相关文章
- 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)
无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...
- 如何在pyqt中自定义无边框窗口
前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...
- 如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果
亚克力效果 在<如何在pyqt中实现窗口磨砂效果>和<如何在pyqt中实现win10亚克力效果>中,我们调用C++ dll来实现窗口效果,这种方法要求电脑上必须装有MSVC.V ...
- 如何在pyqt中给无边框窗口添加DWM环绕阴影
前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...
- 如何在 Matlab 中绘制带箭头的坐标系
如何在 Matlab 中绘制带箭头的坐标系 如何在 Matlab 中绘制带箭头的坐标系 实现原理 演示效果 完整代码 实现原理 使用 matlab 的绘制函数时,默认设置为一个方框形的坐标系, 图1 ...
- 如何在pyqt中实现窗口磨砂效果
磨砂效果的实现思路 这两周一直在思考怎么在pyqt上实现窗口磨砂效果,网上搜了一圈,全都是 C++ 的实现方法.正好今天查python的官方文档的时候看到了 ctypes 里面的 HWND,想想倒不如 ...
- 如何在pyqt中实现win10亚克力效果
亚克力效果的实现思路 上一篇博客<如何在pyqt中实现窗口磨砂效果> 中实现了win7中的Aero效果,但是和win10的亚克力效果相比,Aero还是差了点内味.所以今天早上又在网上搜了一 ...
- 如何在 pyqt 中捕获并处理 Alt+F4 快捷键
前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...
- 如何在unity中使用龙骨动画
龙骨 龙骨是Egret公司的一个用来做动画的软件,本文分享一下如何在Unity2D中使用龙骨导出的2D动画 导出动画 在龙骨中文件->导出,导出动画数据和纹理到Unity的项目中,如果打包了的话 ...
随机推荐
- Cornfields(poj2019)
Cornfields Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6798 Accepted: 3315 Descri ...
- 圆桌问题(hdu4841)
圆桌问题 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submi ...
- 如何让 Spring Security 「少管闲事」
记两种让 Spring Security「少管闲事」的方法. 遇到问题 一个应用对外提供 Rest 接口,接口的访问认证通过 Spring Security OAuth2 控制,token 形式为 J ...
- matplotlib 进阶之Customizing Figure Layouts Using GridSpec and Other Functions
目录 对Gridspec的一些精细的调整 利用SubplotSpec fig.add_grdispec; gs.subgridspec 一个利用Subplotspec的复杂例子 函数链接 matplo ...
- CapstoneCS5210|CS5210低BOM成本方案CS5210|HDMI转VGA芯片方案
Capstone最新推出的一款HDMI转VGA音视频转接线或者转换器方案芯片CS5210. 其设计的优势在于内置晶振,外围电路器件较少设计简单,芯片封装集成度较高,方案BOM成本低,相比其他方案产品更 ...
- Mysql 设计超市经营管理系统,包括员工库存表(stock) 和 仓库表(warehouse)
互联网技术学院周测机试题(三) 一.需求分析 为进一步完善连锁超市经营管理,提高管理效率,减少管理成本,决定开发一套商品管理系统,用于日常的管理.本系统分为商品管理.员工管理.店铺管理,库存管理等功能 ...
- 一键抠除路人甲,昇腾CANN带你识破神秘的“AI消除术”
摘要:都说人工智能改变了生活,你感觉到了么?AI的魔力就在你抠去路人甲的一瞬间来到了你身边.今天就跟大家聊聊--神秘的"AI消除术". 引语 旅途归来,重温美好却被秀丽河山前的路人 ...
- Linux架构中代理服务器配置与负载均衡
本期内容概要 代理 负载均衡 内容详细 1.代理 1.主要作用: 将流量平均分配 2.代理的方式 01 正向代理 外部想要访问服务器 先找代理 找到之后还需要找服务器 应用:VPN 02 反向代理 外 ...
- Net 实现自定义Aop
引言 何为AOP,在软件开发中,总是听到这个AOP这个词语,但是何为AOP呢,AOP全称是Aspect Oriented Programming,中文译为面向切面编程,什么意思呢,即我们的应用程序在运 ...
- vue js格式化数字为金额格式
/** * @description 格式化金额 * @param number:要格式化的数字 * @param decimals:保留几位小数 默认0位 * @param decPoint:小数点 ...