【问题标题】:How to show tooltip image when hover on button pyqt5悬停在按钮pyqt5上时如何显示工具提示图像
【发布时间】:2020-09-24 20:36:52
【问题描述】:

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

但是,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

【问题讨论】:

    标签: python-3.x pyqt5


    【解决方案1】:

    Qt 的工具提示支持富文本格式(只有基本的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)
    

    【讨论】:

    • gif 文件看起来像 png,我该如何解决?将 .gif 添加到文件路径也不起作用
    • @4rigen 你是什么意思?如果您询问动画 gif,它们在工具提示(或任何基于 QTextDocument 的小部件)中不受支持,您需要另一种方式来显示它们。
    • @4rigen 我已经编辑了答案以包括动画 gif 支持。
    • 我做了自动文件扩展功能,但需要很长时间。如何减少文件扩展时间? link
    • @4rigen 你为什么要那样做?!?在加载图像之前绝对不需要检查图像的内容。
    【解决方案2】:

    PySide: Add images to tooltips

    此解决方案适用于我的问题

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-03
      • 1970-01-01
      • 2018-07-09
      • 2017-01-30
      • 2021-10-02
      • 1970-01-01
      • 2015-12-07
      相关资源
      最近更新 更多