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™.
Tooltips for syntax highlights in QTextEdit/QPlainTextEdit by Stephan Sokolow is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
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.