3

self.boundingRect() give me dashed line dimensions shown in image. i need to get opaque area (where actual text is drawn) I tried getting

self.opaqueArea()

but it returns QPainterPath object, which seems pretty complicated and apparently doesn't have width or height functions etc as its representation of complicated path objects. Q. Is there an easier way to calculate that. any ideas.. thanks in advance easies way to get blue area rect

print ("TEXT BOUNDING RECT:",self.boundingRect())
print ("TEXT OPAQUE AREA  :",self.document().size())
print ("TEXT OPAQUE AREA BR size  :",self.opaqueArea().boundingRect().size())

output:

TEXT BOUNDING RECT: PyQt5.QtCore.QRectF(0.0, 0.0, 590.0, 56.0)
TEXT OPAQUE AREA  : PyQt5.QtCore.QSizeF(590.0, 56.0)
TEXT OPAQUE AREA BR size  : PyQt5.QtCore.QSizeF()
haseeb
  • 190
  • 3
  • 12

1 Answers1

3

QGraphicsTextItem internally uses a QTextDocument to manage the text. You can access this through .document(). The text document has a size property, which returns a QPointF.

 self.document().size()

Unfortunately all the methods for this document return a standard rect of the bounding box. However, it is possible to make the text box re-adjust itself to the size of the text it contains. It doesn't quite get down to pixel level (due to line height padding) but it's close.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.view = QGraphicsView()

        scene = QGraphicsScene()

        t = QGraphicsTextItem("Sample\n Text")
        font = t.font()
        font.setPointSize(40)
        font.setWeight(600)
        t.setFont(font)
        t.setTextWidth(400)
        scene.addItem(t)

        rect = t.boundingRect()
        r = QGraphicsRectItem(rect)
        r.setPen(QColor('red'))
        scene.addItem(r)

        d = t.document()
        d.setDocumentMargin(0)
        d.adjustSize()
        rect = t.boundingRect()

        r = QGraphicsRectItem(rect)
        r.setPen(QColor('blue'))
        scene.addItem(r)


        self.view.setScene(scene)

        self.setCentralWidget(self.view)




if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()

The above will give the following result —

Image showing the original bounding box and the cropped one.

The only other idea I had was to get a QPainterPath from the text document and calculate that QRect, but it doesn't appear to be easily accessible. One alternative would be to paint it to a QPainter and crop it there — but there is no built in cropping functionality in Qt.

mfitzp
  • 15,275
  • 7
  • 50
  • 70
  • i tried this and document().size() returning same bounding box. i actually wanted to get dimensions of blue rect, i highlighted, i see, this is not opaque, but still this is minimum area, where drawing is happening. – haseeb Feb 17 '19 at 11:48
  • @lala that is weird. I've updated the answer with another option which gets the bounding rect of the painter path. – mfitzp Feb 17 '19 at 11:53
  • 1
    thanks for help, i edit question and put code / output there as well. Also if you are curious, why i need to do this, ffmpeg rendering (textfilter) did this to text. so second option come to my mind is add offsets based on font size percentage to get closer to pixel perfection. – haseeb Feb 17 '19 at 12:35
  • @lala updated again, getting closer. Maybe close enough? – mfitzp Feb 17 '19 at 15:05