Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-110735

Inconsistent QToolTip expire timeout when using rich text content

    XMLWordPrintable

Details

    • 285c326ef (dev), 742f497ba (6.5)

    Description

      While the restartExpireTimer() function of QTipLabel works fine for generic usage, it always uses the label's text() to compute the expire timer. Since QLabel (and, thus, QToolTip) allows rich text, and text() always returns the source text (including the full HTML code), this results in inconsistent timeouts for the expire timer. That's not a big issue, for simple formatting tags, but things change when the HTML becomes more complex.

      Luckily, QTextDocument supports base64 images in the HTML, so we can embed serialized image data in the document, meaning that we can show embedded images in tooltips too. Unfortunately, this also creates an issue for QToolTip: since the QLabel text always returns the raw text, the computation becomes completely inconsistent even with very small images.

      The following example uses a relatively small pixmap (64x64), and the difference is clear: the text is the same, with the only difference of the image for the second button. While the existence of an image could justify an increase in the timeout, the difference is clearly excessive and becomes somehow massive even for slightly bigger images.

      Sorry for providing PyQt code, but I'm quite sure that there would be no difference with PySide, as the issue is clearly on the Qt side.

      import sys
      from PyQt5.QtCore import *
      from PyQt5.QtGui import *
      from PyQt5.QtWidgets import *

      class ToolTipButton(QPushButton):
          def event(self, event):
              if event.type() == event.ToolTip:
                  default = 10000 + 40 * max(0, len(self.toolTip()) - 100)
                  QTimer.singleShot(default, lambda: 
                      print('hiding tooltip after {:.2f}'.format(default * .001)))
                  doc = QTextDocument()
                  doc.setHtml(self.toolTip())
                  shouldBe = 10000 + 40 * max(0, len(doc.toPlainText()) - 100)
                  if default != shouldBe:
                      QTimer.singleShot(shouldBe, lambda: print('should hide now'))
                  print('showing tooltip; should hide in {:.2f}'.format(
                      shouldBe * .001))
              return super().event(event)

      class Test(QWidget):
          def {}init{}(self):
              super().{}init{}()
              layout = QVBoxLayout(self)
              b1 = ToolTipButton(toolTip='test')
              b2 = ToolTipButton()
              img = QPixmap(64, 64)
              img.fill(Qt.white)
              b2.setIcon(QIcon(img))
              ba = QByteArray()
              buf = QBuffer(ba)
              img.save(buf, 'PNG')
              b2.setToolTip('test<br><img src="data:image/png;base64,{}">'.format(
                  bytes(ba.toBase64()).decode()))
              layout.addWidget(b1)
              layout.addWidget(b2)

      app = QApplication(sys.argv)
      w = Test()
      w.show()
      sys.exit(app.exec())

       

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            matthias_rauter Matthias Rauter
            musicamante Maurizio Berti
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes