前言

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的更多相关文章

  1. 如何在pyqt中自定义无边框窗口

    前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...

  2. 如何在pyqt中自定义SwitchButton

    前言 网上有很多 SwitchButton 的实现方式,大部分是通过重写 paintEvent() 来实现的,感觉灵活性不是很好.所以希望实现一个可以联合使用 qss 来更换样式的 SwitchBut ...

  3. 如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果

    亚克力效果 在<如何在pyqt中实现窗口磨砂效果>和<如何在pyqt中实现win10亚克力效果>中,我们调用C++ dll来实现窗口效果,这种方法要求电脑上必须装有MSVC.V ...

  4. 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)

    无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...

  5. 如何在pyqt中给无边框窗口添加DWM环绕阴影

    前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...

  6. 如何在 pyqt 中捕获并处理 Alt+F4 快捷键

    前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...

  7. 如何在pyqt中实现带动画的动态QMenu

    弹出菜单的视觉效果 QLineEdit 原生的菜单弹出效果十分生硬,而且样式很丑.所以照着Groove中单行输入框弹出菜单的样式和动画效果写了一个可以实现动态变化Item的弹出菜单,根据剪贴板的内容是 ...

  8. 6.1 如何在spring中自定义xml标签

    dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 package ...

  9. 如何在pyqt中实现窗口磨砂效果

    磨砂效果的实现思路 这两周一直在思考怎么在pyqt上实现窗口磨砂效果,网上搜了一圈,全都是 C++ 的实现方法.正好今天查python的官方文档的时候看到了 ctypes 里面的 HWND,想想倒不如 ...

随机推荐

  1. Message: 'geckodriver' executable needs to be in PATH

    1.下载geckodriver.exe:下载地址:mozilla/geckodriver请根据系统版本选择下载:(如Windows 64位系统) 2.下载解压后将getckodriver.exe复制到 ...

  2. PAT B1015德才论

    题目描述: 宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不 ...

  3. uni-app中实现左侧导航栏效果

    HTML: 1 <view class="list"> 2 <!-- 一级 --> 3 <scroll-view class="list-l ...

  4. 猿人学python爬虫第一题

    打开网站.F12,开启devtools.发现有段代码阻止了我们调试 好的.接下来有几种解决方法 1- 绕过阻止调试方法 方法1(推荐) 鼠标放在debugger该行,左边数字行号那一列.右键选择不在永 ...

  5. 帝国cms输出 自增数字 方法大全

    帝国cms输出 自增数字 方法大全 1.帝国cms中调用序号 万能标签调用 使用:[!--no.num--] 标签模板: <li><span>[!--no.num--]< ...

  6. 《手写Mybatis》第4章:Mapper XML的解析和注册使用

    作者:小傅哥 系列:https://bugstack.cn/md/spring/develop-mybatis/2022-03-20-%E7%AC%AC1%E7%AB%A0%EF%BC%9A%E5%B ...

  7. Typora+PicGO+Gitee实现图床功能

    Typora+PicGO+Gitee实现图床功能 版本 typora(0.9.86) PicGo(2.3.0) 主要参考链接 出现问题就先看看这个 问题一 打开PicGo后安装github插件会一直安 ...

  8. thinkphp6事件监听event-listene

    事件系统可以看成是行为系统的升级版,相比行为系统强大的地方在于事件本身可以是一个类,并且可以更好的支持事件订阅者. 事件相比较中间件的优势是事件比中间件更加精准定位(或者说粒度更细),并且更适合一些业 ...

  9. vue--vuex 中 Modules 详解

    前言 在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理.于是Vuex中就存在了另 ...

  10. 伪元素 Before & Aster

    1. html 结构 <label class="is-required" for="name">姓名</label> <inpu ...