qtpyqtpyqt5qpainterqfontmetrics

Qt wrapping text in boundingRect


I am writing an application in PyQt and I need to wrap the text that I am painting. I use boundingRect method of QFontMetrics class to define the size and then QPainter.drawText to draw. I need the text to fit in a given rectangle. This is the line I use:

rect = metrics.boundingRect(rect, Qt.TextWordWrap, text)

However, due to the flag Qt.TextWordWrap, if the text doesn't have any spaces it doesn't wrap and will not fit in the rectangle. I tried Qt.TextWrapAnywhere but this breaks the words apart even when there are spaces. The Qt.TextFlag doesn't seem to have any flag, that prioritize wrapping words and only if it is impossible, breaks the words apart, like QTextOption.WrapAtWordBoundaryOrAnywhere. Is there a way to wrap text like this using boundingRect and drawText?


Solution

  • For situations like these, it's usually better to use a QTextDocument, which allows using more advanced options.

    wrapped label

    class WrapAnywhereLabel(QtWidgets.QWidget):
        def __init__(self, text=''):
            super().__init__()
            self.doc = QtGui.QTextDocument(text)
            self.doc.setDocumentMargin(0)
            opt = QtGui.QTextOption()
            opt.setWrapMode(opt.WrapAtWordBoundaryOrAnywhere)
            self.doc.setDefaultTextOption(opt)
    
        def hasHeightForWidth(self):
            return True
    
        def heightForWidth(self, width):
            self.doc.setTextWidth(width)
            return self.doc.size().height()
    
        def sizeHint(self):
            return self.doc.size().toSize()
    
        def resizeEvent(self, event):
            self.doc.setTextWidth(self.width())
    
        def paintEvent(self, event):
            qp = QtGui.QPainter(self)
            self.doc.drawContents(qp, QtCore.QRectF(self.rect()))
    
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = WrapAnywhereLabel('hellooooo hello hellooooooooooooooo')
    w.show()
    sys.exit(app.exec_())