如何在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的项目中,如果打包了的话 ...
随机推荐
- hdu 4549 M斐波那契数列(快速幂 矩阵快速幂 费马小定理)
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4549: 题目是中文的很容易理解吧.可一开始我把题目看错了,这毛病哈哈. 一开始我看错题时,就用了一个快速 ...
- fastapi(一)
废话不多说,直接上代码. 目录结构, 由于我也是刚开始学这个框架,只是了解了怎么注册蓝图,JWT的集成,数据库的集成,想了解更多,自行打开官方文档去详细阅读.fastapi官网文档链接 创建一个mai ...
- 分割字符串StringTokenizer
StringTokenizer 原来是一个遗留类,并未被废弃,只是出于兼容性原因而被保留,在新代码中已经不鼓励使用它了,建议使用 String 的 split 方法或 java.util.regex ...
- IOS 如何获取app更新链接 如【itms-apps://itunes.apple.com/cn/app/id1362432761?mt=8】
这是iTunes接口地址 ,有兴趣可以看一下,我们要用到的接口如下,xxx 处换成自己 App 的 AppId ,AppId 可以在 iTunes Connect 里面看到. http://itune ...
- Java初学者作业——简单程序根据用户输入的会员类型以及购物金额,判断是否能够享受活动优惠
返回本章节 返回作业目录 需求说明: 超市周年庆举行购物满减活动,编写Java程序,根据用户输入的会员类型以及购物金额,判断是否能够享受活动优惠,会员类型的输入不限制大小写.具体获取规则:若为VIP会 ...
- 编写Java程序,车站只剩 50 张从武汉到北京的车票,现有 3 个窗口售卖,用程序模拟售票的过程,使用Runnable解决线程安全问题
查看本章节 查看作业目录 需求说明: 车站只剩 50 张从武汉到北京的车票,现有 3 个窗口售卖,用程序模拟售票的过程,要求使用同步方法保证售票过程中票数的正确性 实现思路: 创建 Java 项目,在 ...
- linux 设置开机自动启动应用
作为一个开发,项目现在一般都是部署在虚拟机上的linux,数据库也是按照在l虚拟机上的linux,一旦关机了,在开机程序都没打开,又要一个个去开,很麻烦,所以现在我现在使用supervisor去做一个 ...
- for update未提交导致锁表
select for update 是为了在查询时,避免其他用户以该表进行插入,修改或删除等操作,造成表的不一致性. 应用场景: 什么时候需要使用for update?就是那些需要业务层面数据独占时, ...
- minio实现文件上传下载和删除功能
https://blog.csdn.net/tc979907461/article/details/106673570?utm_medium=distribute.pc_relevant_t0.non ...
- kubernetes 之部署metrics-server
Kubernetes 版本是 1.14 # kubectl version --short Client Version: v1.14.3 Server Version: v1.14.2 下载文件 f ...