如何在 pyqt 中自定义工具提示 ToolTip
前言
Qt 自带的工具提示样式不太好看,就算加了样式表也时不时会失效,同时工具提示没有阴影,看起来就更难受了。所以本篇博客将会介绍自定义工具提示的方法,效果如下图所示:

实现过程
工具提示其实就是一个带了标签的窗口,为了给工具提示加上阴影,只要给窗口设置 QGraphicsShadowEffect 即可。同时 QToolTip 弹出之后不会一直卡在界面上,一段时间后就会消失,所以我们应该给自定义的工具提示加上一个 QTimer,时间溢出之后就隐藏工具提示。
# coding:utf-8
from PyQt5.QtCore import QFile, QPropertyAnimation, QTimer, Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect,
QHBoxLayout, QLabel)
class ToolTip(QFrame):
def __init__(self, text='', parent=None):
super().__init__(parent=parent)
self.__text = text
self.__duration = 1000
self.timer = QTimer(self)
self.hBox = QHBoxLayout(self)
self.label = QLabel(text, self)
self.ani = QPropertyAnimation(self, b'windowOpacity', self)
# set layout
self.hBox.addWidget(self.label)
self.hBox.setContentsMargins(10, 7, 10, 7)
# add shadow
self.shadowEffect = QGraphicsDropShadowEffect(self)
self.shadowEffect.setBlurRadius(32)
self.shadowEffect.setColor(QColor(0, 0, 0, 60))
self.shadowEffect.setOffset(0, 5)
self.setGraphicsEffect(self.shadowEffect)
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.hide)
# set style
self.setAttribute(Qt.WA_StyledBackground)
self.setDarkTheme(False)
self.__setQss()
def text(self):
return self.__text
def setText(self, text: str):
""" set text on tooltip """
self.__text = text
self.label.setText(text)
self.label.adjustSize()
self.adjustSize()
def duration(self):
return self.__duration
def setDuration(self, duration: int):
""" set tooltip duration in milliseconds """
self.__duration = abs(duration)
def __setQss(self):
""" set style sheet """
f = QFile("resource/tooltip.qss")
f.open(QFile.ReadOnly)
self.setStyleSheet(str(f.readAll(), encoding='utf-8'))
f.close()
self.label.adjustSize()
self.adjustSize()
def setDarkTheme(self, dark=False):
""" set dark theme """
dark = 'true' if dark else 'false'
self.setProperty('dark', dark)
self.label.setProperty('dark', dark)
self.setStyle(QApplication.style())
def showEvent(self, e):
self.timer.stop()
self.timer.start(self.__duration)
super().showEvent(e)
def hideEvent(self, e):
self.timer.stop()
super().hideEvent(e)
工具提示继承自 QFrame 的原因是我们需要设置边框样式,样式表如下所示,支持亮暗两种主题:
ToolTip[dark="false"] {
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 5px;
background-color: rgb(243, 243, 243);
}
ToolTip[dark="true"] {
border: 1px solid rgb(28, 28, 28);
border-radius: 5px;
background-color: rgb(43, 43, 43);
}
QLabel {
background-color: transparent;
font: 15px 'Segoe UI', 'Microsoft YaHei';
}
QLabel[dark="false"] {
color: black;
}
QLabel[dark="true"] {
color: white;
}
测试
下述代码的运行效果就是动图中所示的样子,只要给想要设置工具提示的部件安装上事件过滤器,就能将 QToolTip 替换成自定义的工具提示:
# coding:utf-8
import sys
from PyQt5.QtCore import QEvent, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
from tool_tip import ToolTip
class Demo(QWidget):
def __init__(self):
super().__init__()
self.hBox = QHBoxLayout(self)
self.button1 = QPushButton('キラキラ', self)
self.button2 = QPushButton('食べた愛', self)
self._toolTip = ToolTip(parent=self)
# self._tooltip.setDarkTheme(True)
self.button1.setToolTip('aiko - キラキラ ')
self.button2.setToolTip('aiko - 食べた愛 ')
self.button1.setToolTipDuration(1000)
self.button2.setToolTipDuration(5000)
self.button1.installEventFilter(self)
self.button2.installEventFilter(self)
self.hBox.setContentsMargins(30, 30, 30, 30)
self.hBox.setSpacing(20)
self.hBox.addWidget(self.button1)
self.hBox.addWidget(self.button2)
self.resize(600, 300)
self._toolTip.hide()
with open('resource/demo.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
def eventFilter(self, obj, e: QEvent):
if obj is self:
return super().eventFilter(obj, e)
tip = self._toolTip
if e.type() == QEvent.Enter:
tip.setText(obj.toolTip())
tip.setDuration(obj.toolTipDuration())
pos = obj.mapTo(self, QPoint(0, 0))
x = pos.x() + obj.width()//2 - tip.width()//2
y = pos.y() - 5 - tip.height()
# adjust postion to prevent tooltips from appearing outside the window
x = min(max(5, x), self.width() - tip.width() - 5)
y = min(max(5, y), self.height() - tip.height() - 5)
tip.move(x, y)
tip.show()
elif e.type() == QEvent.Leave:
tip.hide()
elif e.type() == QEvent.ToolTip:
return True
return super().eventFilter(obj, e)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()
用到的样式文件如下:
QWidget{
background-color: white;
}
QPushButton {
background-color: rgb(204, 204, 204);
padding: 10px 64px 10px 64px;
font: 19px 'Microsoft YaHei';
border: transparent;
border-radius: 4px;
}
QPushButton:pressed:hover {
background-color: rgb(153, 153, 153);
}
QPushButton:hover {
background-color: rgb(230, 230, 230);
}
QPushButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
后记
自定义工具提示的方法已经介绍完了,更多好康的自定义小部件参见 GitHub 仓库 https://github.com/zhiyiYo/PyQt-Fluent-Widgets,以上~~
如何在 pyqt 中自定义工具提示 ToolTip的更多相关文章
- 如何在pyqt中自定义无边框窗口
前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...
- 如何在pyqt中自定义SwitchButton
前言 网上有很多 SwitchButton 的实现方式,大部分是通过重写 paintEvent() 来实现的,感觉灵活性不是很好.所以希望实现一个可以联合使用 qss 来更换样式的 SwitchBut ...
- 如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果
亚克力效果 在<如何在pyqt中实现窗口磨砂效果>和<如何在pyqt中实现win10亚克力效果>中,我们调用C++ dll来实现窗口效果,这种方法要求电脑上必须装有MSVC.V ...
- 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)
无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...
- 如何在pyqt中给无边框窗口添加DWM环绕阴影
前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...
- 如何在 pyqt 中捕获并处理 Alt+F4 快捷键
前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...
- 如何在pyqt中实现带动画的动态QMenu
弹出菜单的视觉效果 QLineEdit 原生的菜单弹出效果十分生硬,而且样式很丑.所以照着Groove中单行输入框弹出菜单的样式和动画效果写了一个可以实现动态变化Item的弹出菜单,根据剪贴板的内容是 ...
- 6.1 如何在spring中自定义xml标签
dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 package ...
- 如何在pyqt中实现窗口磨砂效果
磨砂效果的实现思路 这两周一直在思考怎么在pyqt上实现窗口磨砂效果,网上搜了一圈,全都是 C++ 的实现方法.正好今天查python的官方文档的时候看到了 ctypes 里面的 HWND,想想倒不如 ...
随机推荐
- canvas实现平铺水印
欲实现的水印平铺的效果图如下: 从图上看,应该做到以下几点: 文字在X和Y方向上进行平铺: 文字进行了一定的角度的旋转: 水印作为背景,其z-index位置应位于页面内容底部, 即不能覆盖页面主内容: ...
- Android M 版本以后的特殊权限问题分析
现象 桌面悬浮框在6.0以后,会因为SYSTEM_ALERT_WINDOW权限的问题,无法在最上层显示. 问题原因 SYSTEM_ALERT_WINDOW,设置悬浮窗,进行一些黑科技 WRITE_SE ...
- IO流入门+简单案例实现
IO流 总结内容 1. IO流是什么 2. 字符流和字节流 3. File常用API(前面类型为返回类型) 4. 编码转换 5. IO流实现流程 6. 输入输出流简单实现 7. 输入输出流简单实现 总 ...
- 小程序colorui框架引入与使用
colorui是UI框架: 超好用的一款 小程序二维码体验: : 引入方式: 1.先去下载colorui https://github.com/weilanwl/ColorUI 把col ...
- FastAPI(七十)实战开发《在线课程学习系统》接口开发--留言功能开发
在之前的文章:FastAPI(六十九)实战开发<在线课程学习系统>接口开发--修改密码,这次分享留言功能开发 我们能梳理下对应的逻辑 1.校验用户是否登录 2.校验留言的用户是否存在 3. ...
- FastAPI(六十七)实战开发《在线课程学习系统》接口开发--用户登陆接口开发
接上一篇文章FastAPI(六十六)实战开发<在线课程学习系统>接口开发--用户注册接口开发.这次我们分享实际开发--用户登陆接口开发. 我们先来梳理下逻辑 1.查询用户是否存在2.校验密 ...
- mybatis-day1入门案例
首先应先创建maven工程 (jar包要导入,五个核心jar包) 如果测试运行时出现了不支持版本5,则要修改以下内容 类的路径如下 1.配置pom.xml依赖 <?xml version=&qu ...
- 用来创建用户docker registry认证的Secret
集群环境:1.k8s用的是二进制方式安装2.操作系统是linux (centos)3.操作系统版本为 7.4/7.94.k8s的应用管理.node管理.pod管理等用rancher.k8s令牌以及ma ...
- 黑客入门——渗透必备神器Burpsuit的安装和简单使用教程
很多人没有听说过burp全称(BurpSuite)BurpSuite是一款白帽子,黑帽子渗透测试必备工具,通过拦截HTTP/HTTPS的web数据包,当浏览器和相关应用程序的中间人,进行拦截.修改 ...
- pgpool-II 4.3 中文手册-前言
什么是 Pgpool-II? Pgpool II 管理一个 PostgreSQL 服务器池,以实现单个 PostgreSQL 安装无法实现的一些功能.这些功能包括: 高可用 Pgpool-II 通过使 ...