DayOftheNewDan.com
Text Balloon in a QGraphicsView
December 12, 2012
Lately I have been doing some development using the Qt Framework and the PySide Python bindings. For my application I wanted a nice looking text balloon to label some points on a graph. First I subclassed QGraphicsTextItem and wrote new boundingRect() and paint() methods. The balloon can appear either below or above the point on the graph, so the bounding rect needs to be adjusted to handle this extra height.
Here is the relevant portion of the class:
class GraphicsBalloonTextItem(QtGui.QGraphicsTextItem):
"""
This class draws a nice text balloon. The balloon can be
pointing above or below depending upon the orientation attribute.
"""
def __init__(self, parent, orientation='above'):
super(GraphicsBalloonTextItem, self).__init__(parent)
self.orientation = orientation
def boundingRect(self):
"""
Returns the new bounding rect which makes room for the
balloon label and arrow.
"""
rect = super(GraphicsBalloonTextItem, self).boundingRect()
if self.orientation == 'above':
# balloon above the point
return rect.adjusted(-1, 0, 1, 12)
else:
# balloon below the point
return rect.adjusted(-1, -12, 1, 0)
def paint(self, painter, option, widget):
"""
This method does the drawing.
"""
painter.setPen(QtCore.Qt.darkGray)
painter.setBrush(QtGui.QColor(250, 245, 209))
adjustedRect = self.boundingRect() # the rectangle around the text
if self.orientation == 'above':
# should draw the label balloon above the point
adjustedRect.adjust(0, 0, 0, -12)
vertices = [QtCore.QPointF(adjustedRect.width()/2 - 6,
adjustedRect.height() - 1),
QtCore.QPointF(adjustedRect.width()/2,
adjustedRect.height() + 12),
QtCore.QPointF(adjustedRect.width()/2 + 6,
adjustedRect.height() - 1)]
else:
# should draw the label balloon below the point
adjustedRect.adjust(0, 12, 0, 0)
vertices = [QtCore.QPointF(adjustedRect.width()/2 - 6, 1),
QtCore.QPointF(adjustedRect.width()/2, -12),
QtCore.QPointF(adjustedRect.width()/2 + 6, 1)]
# paint the balloon rectangle
painter.drawRoundedRect(adjustedRect, 8, 8)
# paint the balloon arrow triangle fill
painter.setPen(QtCore.Qt.NoPen)
painter.drawPolygon(vertices)
# paint the balloon arrow triangle stroke
painter.setPen(QtCore.Qt.darkGray)
painter.drawLine(vertices[0], vertices[1])
painter.drawLine(vertices[2], vertices[1])
# Finally call the parent paint method to draw the actual text
super(GraphicsBalloonTextItem, self).paint(painter, option, widget)