Tooltips for syntax highlights in QTextEdit/QPlainTextEdit

While I was experimenting with adding nlprule-based grammar-checking to my spell-checked QPlainTextEdit subclass (not yet polished enough to share, but there’s a cut-down proof of concept for the nlprule integration on StackOverflow if you want it), I ran into a little problem.

Apparently, there’s an unresolved bug (QTBUG-80524 and duplicates) where QTextEdit and QPlainTextEdit don’t take syntax highlighter-set changes into account when figuring out whether to display a tooltip and what to show.

The solution? Override the lookup behaviour. Here’s how you do it:

class TooltipPlainTextEdit(QPlainTextEdit):
    def __init__(self, *args):
        QPlainTextEdit.__init__(self, *args)

        # Opt in to the events we need to override
        self.setMouseTracking(True)

    def event(self, event) -> bool:
        """Reimplement tooltip lookup to get nlprule messages working"""
        if event.type() == QEvent.ToolTip:
            # Get a secondary text cursor, taking margins into account
            pos = event.pos()
            pos.setX(pos.x() - self.viewportMargins().left())
            pos.setY(pos.y() - self.viewportMargins().top())
            cursor = self.cursorForPosition(pos)

            # QTextCursor doesn't have a quicker way to get
            # highlighter-applied formats, so find the one that our
            # cursor is inside
            for fmt in cursor.block().layout().formats():
                if (fmt.start <= cursor.position() and
                        fmt.start + fmt.length >= cursor.position()):

                    # Calculate the bounding box for the text and feed
                    # it as the rectangle for requesting that the
                    # tooltip auto-hide when the cursor exits
                    cursor.setPosition(fmt.start)
                    cursor.setPosition(fmt.start + fmt.length,
                                       QTextCursor.KeepAnchor)
                    QToolTip.showText(event.globalPos(), fmt.format.toolTip(),
                        self, self.cursorRect(cursor))
                    return True

        # Fall back to the default behaviour
        return super(TooltipPlainTextEdit, self).event(event)

…and that’s it. Your QTextCharFormat.setToolTip calls should now Just Work™.

CC BY-SA 4.0 Tooltips for syntax highlights in QTextEdit/QPlainTextEdit by Stephan Sokolow is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

This entry was posted in Geek Stuff. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution under the same terms as the associated post.

All comments are moderated. If your comment is generic enough to apply to any post, it will be assumed to be spam. Borderline comments will have their URL field erased before being approved.