将鼠标悬停在按钮pyqt5上时如何显示工具提示图像

时间:2020-03-04 08:29:29

标签: python-3.x pyqt5

我想在将鼠标悬停在按钮上时显示图像。

但是,pyqt5工具提示参考仅包含文本。

我该怎么做?我想像下面的循环元素那样动态地做

我需要填写代码

def createButtons(self):
    for d_name in dic:
        btn = QPushButton(d_name, self)
        btn.clicked.connect(lambda state, x=d_name: self.btn_clicked(x))
        # btn.addTooltipImage(d_name)
        self.button_map[btn.text()] = btn

2 个答案:

答案 0 :(得分:1)

PySide: Add images to tooltips

此解决方案适用我的问题

btn.setToolTip('<br><img src="%s">' % (iconpath))

答案 1 :(得分:1)

Qt的工具提示支持RTF格式(仅基本的subset of HTML),因此<img>标签可用:

self.button.setToolTip('<img src="icon.svg">')

请记住,如果您使用的是本地文件路径,则它必须是绝对路径或相对于加载它的文件路径。

另一种方法是使用Qt的resource system:您可以在Designer中创建资源文件,然后使用pyrcc myresource.qrc -o myresource.py进行构建,使用import myresource进行导入,并使用冒号前缀加载图像路径:

self.button.setToolTip('<img src=":/images/icon.svg">')

动画工具提示(GIF)

工具提示与基于QTextDocument的任何其他窗口小部件一样,均不支持动画。唯一的解决方案是创建一个行为像工具提示的自定义窗口小部件。

为此,最合乎逻辑的方法是将QLabel子类化,该类支持QMovie类,该类提供对动画图像的支持。

请注意,这并不容易:虽然工具提示看似非常简单的对象,但其行为遵循用户认为理所当然的许多方面。为了模仿这种行为,必须以相同的方式精心设计子类。

class ToolTipAnimation(QtWidgets.QLabel):
    def __init__(self, parent, file, width=None, height=None):
        super().__init__(parent, flags=QtCore.Qt.ToolTip)
        self.setMouseTracking(True)

        # image loading doesn't happen immediately, as it could require some time;
        # we store the information for later use
        self._file = file
        self._width = width
        self._height = height
        self._shown = False

        # a timer that prevents the enterEvent to hide the tip immediately
        self.showTimer = QtCore.QTimer(interval=100, singleShot=True)

        # install an event filter for the application, so that we can be notified
        # whenever the user performs any action
        QtWidgets.QApplication.instance().installEventFilter(self)

    def load(self):
        movie = QtGui.QMovie(self._file)
        if self._width and not self._height:
            self._height = self._width
        if self._width and self._height:
            size = QtCore.QSize(self._width, self._height)
            movie.setScaledSize(size)
        else:
            size = QtCore.QSize()
            for f in range(movie.frameCount()):
                movie.jumpToFrame(f)
                size = size.expandedTo(movie.currentImage().size())
        self.setFixedSize(size)
        self.setMovie(movie)
        self._shown = True

    def show(self, pos=None):
        if not self._shown:
            self.load()
        if pos is None:
            pos = QtGui.QCursor.pos()
        # ensure that the tooltip is always shown within the screen geometry
        for screen in QtWidgets.QApplication.screens():
            if pos in screen.availableGeometry():
                screen = screen.availableGeometry()
                # add an offset so that the mouse cursor doesn't hide the tip
                pos += QtCore.QPoint(2, 16)
                if pos.x() < screen.x():
                    pos.setX(screen.x())
                elif pos.x() + self.width() > screen.right():
                    pos.setX(screen.right() - self.width())
                if pos.y() < screen.y():
                    pos.setY(screen.y())
                elif pos.y() + self.height() > screen.bottom():
                    pos.setY(screen.bottom() - self.height())
                break

        self.move(pos)
        super().show()
        self.movie().start()

    def maybeHide(self):
        # if for some reason the tooltip is shown where the mouse is, we should
        # not hide it if it's still within the parent's rectangle
        if self.parent() is not None:
            parentPos = self.parent().mapToGlobal(QtCore.QPoint())
            rect = QtCore.QRect(parentPos, self.parent().size())
            if QtGui.QCursor.pos() in rect:
                return
        self.hide()

    def eventFilter(self, source, event):
        # hide the tip for any user interaction
        if event.type() in (QtCore.QEvent.KeyPress, QtCore.QEvent.KeyRelease, 
            QtCore.QEvent.WindowActivate, QtCore.QEvent.WindowDeactivate, 
            QtCore.QEvent.FocusIn, QtCore.QEvent.FocusOut, 
            QtCore.QEvent.Leave, QtCore.QEvent.Close, 
            QtCore.QEvent.MouseButtonPress, QtCore.QEvent.MouseButtonRelease, 
            QtCore.QEvent.MouseButtonDblClick, QtCore.QEvent.Wheel):
                self.hide()
        return False

    def mouseMoveEvent(self, event):
        QtCore.QTimer.singleShot(100, self.hide)

    def enterEvent(self, event):
        # hide the tooltip when mouse enters, but not immediately, otherwise it
        # will be shown right after from the parent widget
        if not self.showTimer.isActive():
            QtCore.QTimer.singleShot(100, self.hide)

    def showEvent(self, event):
        self.showTimer.start()

    def hideEvent(self, event):
        self.movie().stop()


class ButtonIcon(QtWidgets.QPushButton):
    toolTipAnimation = None
    formats = tuple(str(fmt, 'utf8') for fmt in QtGui.QMovie.supportedFormats())

    def setToolTipImage(self, image, width=None, height=None):
        if not image or self.toolTipAnimation:
            self.toolTipAnimation.hide()
            self.toolTipAnimation.deleteLater()
            self.toolTipAnimation = None
            self.setToolTip('')
            if not image:
                return
        if image.endswith(self.formats):
            self.toolTipAnimation = ToolTipAnimation(self, image, width, height)
        else:
            if width and not height:
                height = width
            if width and height:
                self.setToolTip(
                    '<img src="{}" width="{}" height="{}">'.format(
                        image, width, height))
            else:
                self.setToolTip('<img src="{}">'.format(image))

    def event(self, event):
        if (event.type() == QtCore.QEvent.ToolTip and self.toolTipAnimation and 
            not self.toolTipAnimation.isVisible()):
                self.toolTipAnimation.show(event.globalPos())
                return True
        elif event.type() == QtCore.QEvent.Leave and self.toolTipAnimation:
            self.toolTipAnimation.maybeHide()
        return super().event(event)


class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QHBoxLayout(self)
        buttonFixed = ButtonIcon('fixed image')
        buttonFixed.setToolTipImage('icon.svg')
        layout.addWidget(buttonFixed)
        buttonAnimated = ButtonIcon('animated gif')
        # the size can be set explicitly (if height is not provided, it will
        # be the same as the width)
        buttonAnimated.setToolTipImage('animated.gif', 200)
        layout.addWidget(buttonAnimated)