如何在 pyqt 中自定义工具提示 ToolTip

前言

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

如何在 pyqt 中自定义工具提示 ToolTip

实现过程

工具提示其实就是一个带了标签的窗口,为了给工具提示加上阴影,只要给窗口设置 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,以上~~

Original: https://www.cnblogs.com/zhiyiYo/p/16303940.html
Author: 之一Yo
Title: 如何在 pyqt 中自定义工具提示 ToolTip

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582816/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 如你所见

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月6日
    079
  • 附025.kubeadm部署Kubernetes更新证书

    一 查看证书 提示:由上可知,根证书有效期为10年,其他所有证书有效期为1年。 二 证书类别 由此集群根证书签发的证书有: 提示:kubelet的/var/lib/kubelet/…

    Linux 2023年6月13日
    0122
  • 剑指offer计划29(动态规划困难)—java

    1.1、题目1 剑指 Offer 19. 正则表达式匹配 1.2、解法 动态规划后面再研究 1.3、代码 class Solution { public boolean isMat…

    Linux 2023年6月11日
    0108
  • Java基础系列–09_集合2

    昨天介绍了集合的主要架构体系,今天主要的目的是学习集合的迭代器的遍历和List的特有功能。 迭代器:概述: 由于多种集合的数据结构不同,所以存储方式不同,取出方式也不同。但是他们都…

    Linux 2023年6月7日
    078
  • mybatis-plus详细讲解

    本文笔记都是观看狂神老师视频手敲的,视频地址:https://www.bilibili.com/video/BV17E411N7KN 学java后端的都可以去看一下,从基础到架构很…

    Linux 2023年6月7日
    0120
  • 【转】 一条 SQL 的执行过程详解

    MySQL 体系架构 – 连接池组件 1、负责与客户端的通信,是半双工模式,这就意味着某一固定时刻只能由客户端向服务器请求或者服务器向客户端发送数据,而不能同时进行。 …

    Linux 2023年6月13日
    0128
  • 从磁盘删除Ubuntu出现的问题

    问题描述:Win10+Ubuntu双系统,利用磁盘管理工具删除了Ubuntu占用的磁盘,导致开机直接进入Grub界面,并且启动项仍有Ubuntu。 问题解决: 开机进入BIOS或启…

    Linux 2023年6月14日
    099
  • WPF 已知问题 Popup 吃掉 PreviewMouseDown 事件

    在 WPF 中,使用 Popup 也许会看到 PreviewMouseDown 事件被吃掉 因为 PreviewMouseDown 是 RoutingStrategy.Direct…

    Linux 2023年6月6日
    0126
  • brew install mongodb

    install 安装请参考:https://blog.csdn.net/chanstic/article/details/104371316 //启&…

    Linux 2023年6月6日
    0132
  • 如何在 python 中解决 ImportError: DLL load failed while importing win32api

    问题描述 安装完 pywin32 之后,如果直接在代码中 import win32api 可能会报下述错误: ImportError: DLL load failed while …

    Linux 2023年6月7日
    085
  • Pytorch 中 tensor的维度拼接

    torch.stack() 和 torch.cat() 都可以按照指定的维度进行拼接,但是两者也有区别,torch.satck() 是 增加新的维度进行堆叠,即其维度拼接后会增加一…

    Linux 2023年6月7日
    0104
  • gitlab服务yum源安装详细步骤(centos7)

    gitlab服务yum源安装详细步骤(centos7) 概述 GitLab是利用Ruby on Rails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进…

    Linux 2023年6月8日
    094
  • CSS中content属性的妙用

    前言 本文讲解CSS中使用频率并不高的content属性,通过多个实用的案例,带你由浅入深的掌握content的用法,让代码变得更加简洁、高效。 定义 W3school中这样定义:…

    Linux 2023年6月7日
    0134
  • Redis Persistent Replication Sentinel Cluster的一些理解

    Redis Persistent Replication Sentinel Cluster的一些理解 我喜欢把工作中接触到的各种数据库叫做存储系统,笼统地说:Redis、Mysql…

    Linux 2023年5月28日
    076
  • 三少玩Linux之Debian10.3(buster), win7共存的安装方法

    这个是debian10.3的安装视频:https://www.bilibili.com/video/BV1iE411x7ww, win7就不用教了吧; 先装win7, 再装debi…

    Linux 2023年6月14日
    0100
  • 【Leetcode】64. 最小路径和

    给定一个包含非负整数的 m x n网格 grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动…

    Linux 2023年6月6日
    0100
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球