resizeborderpyqt6qgraphicstextitem

Resize border of qgraphicstextitem


I am adding a QGraphicTextItem to a scene using pyqt6. I cannot resize the widget border when text is resized. I have looked at a few way of resizing, but none work. The text does change to a bigger font via the context menu. The entire class is shown below.

class FreeTextGraphicsItem(QtWidgets.QGraphicsTextItem):
    def __init__(self, x, y, text_):
        super(FreeTextGraphicsItem, self).__init__(None)
        self.x = x
        self.y = y
        self.text = text_
        self.setFlags(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable |
                      QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsFocusable |
                      QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
        self.font = QtGui.QFont(self.settings['font'], 9, QtGui.QFont.Weight.Normal)
        self.setFont(self.font)
        self.setPlainText(self.text)
        self.setPos(self.x, self.y)

    def contextMenuEvent(self, event):
        menu = QtWidgets.QMenu()
        menu.addAction(_("Large font"))
        action = menu.exec(QtGui.QCursor.pos())
        if action is None:
            return
        if action.text() == "Large font":
            self.font = QtGui.QFont(self.settings['font'], 12, QtGui.QFont.Weight.Normal)
        frame = self.document().documentLayout().frameBoundingRect(self.document().rootFrame())
        self.boundingRect().setRect(0, 0, frame.width(), frame.height())

    def paint(self, painter, option, widget):
        color = QtCore.Qt.GlobalColor.white
        painter.setBrush(QtGui.QBrush(color, style=QtCore.Qt.BrushStyle.SolidPattern))
        painter.drawRect(self.boundingRect())
        painter.setFont(self.font)
        fm = painter.fontMetrics()
        painter.setPen(QtGui.QColor(QtCore.Qt.GlobalColor.black))
        lines = self.text.split('\\n')
        for row in range(0, len(lines)):
            painter.drawText(5, fm.height() * (row + 1), lines[row])

Solution

  • You're not using the features of QGraphicsTextItem.
    In fact, you're completely ignoring and overriding most of its aspects:

    If your main purpose is to draw a border around the item, then you should only do that, and then rely on the existing capabilities of the item.

    class FreeTextGraphicsItem(QtWidgets.QGraphicsTextItem):
        def __init__(self, x, y, text_):
            super().__init__(text_.replace('\\n', '\n'))
            self.setPos(x, y)
            self.setFlags(
                QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable
                | QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsFocusable
                | QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsSelectable
            )
            font = QtGui.QFont(self.settings['font'], 9, QtGui.QFont.Weight.Normal)
            self.setFont(font)
            self.setDefaulTextColor(QtGui.QColor(QtCore.Qt.GlobalColor.white))
    
        def contextMenuEvent(self, event):
            menu = QtWidgets.QMenu()
            largeFontAction = menu.addAction(_("Large font"))
            action = menu.exec(event.screenPos())
            if action == largeFontAction:
                font = QtGui.QFont(
                    self.settings['font'], 12, QtGui.QFont.Weight.Normal)
                self.setFont(font)
    
        def paint(self, painter, option, widget=None):
            painter.save()
            painter.setBrush(QtCore.Qt.GlobalColor.white)
            painter.drawRect(self.boundingRect())
            painter.restore()
            super().paint(painter, option, widget)
    

    Note: comparing actions with their text is pointless, other than conceptually wrong; not only you can have a more reliable object-based comparison using the action (as shown above), but that comparison can also become invalid: a menu could contain items that have the same names, and you're also probably using the _ for translations, so the text might not match at all.