Qt has a set of graphical classes that come in 2 variants: with integer precision and floating point precision.
These are the ones I can remember
| QLine | QLineF |
| QMargins | QMarginsF |
| QPoint | QPointF |
| QRect | QRectF |
| QSize | QSizeF |
Apart from the obvious difference, that one uses integers and the other uses floats, as stated in their names and in the official documentation, I have quite a few doubts...
While those classes are often interchangeable and have almost the same implementations, there are peculiar differences in their usage and result.
Integer based classes are mostly used for screen coordinates (widget positions, sizes, etc), which is normally considered based on pixel units (which are obviously integers).
There are important differences when dealing with positioning/collision and drawing, though.
Consider the following:
>>> p = QtCore.QPoint(1, 1)
>>> r = QtCore.QRect(0, 0, 1, 1)
>>> print(r.contains(p))
False
>>> r = QtCore.QRectF(0, 0, 1, 1)
>>> print(r.contains(p))
True
This is because QRect considers only the integer ("pixel") size, and obviously (1, 1) is on "another pixel".
QRect is also peculiar for the right() and bottom() functions, because (as explained in the documentation) they always return left+width-1 and top+height-1 for historical reasons:
>>> r = QtCore.QRect(0, 0, 1, 1)
>>> print(r.right())
0
In light of this, always keep in mind that the same works for the setters of those coordinates (both set* and move*):
>>> r.setRight(1)
>>> print(r)
PyQt5.QtCore.QRect(0, 0, 2, 1)
>>> r.moveRight(0)
>>> print(r)
PyQt5.QtCore.QRect(-1, 0, 2, 1)
Floating point classes also have features not available to integer based ones (mostly because it wouldn't be possible/useful/reasonable to implement them).
For example, the QLineF class:
p1 starting point), or the angle created with another line (or, better, their extensions, if they don't intersect) [1];Floating point classes allow more precise drawing and positioning, which are important aspects when you need antialiased painting or you're dealing with content that can be scaled or is based on proportional values (consider a magnified QGraphicsScene, or text displaying since fonts are vector based).
For instance, the following will give you very different results:
painter.setRenderHints(painter.Antialiasing)
painter.drawRect(QtCore.QRect(1, 1, 2, 2))
painter.drawRect(QtCore.QRectF(1, 1, 2.5, 2.5))
Then, it's important to remember that all simple drawing functions of QPainter that accept numeric values as main parameters will always use integer values (I believe that's due to Python's dynamic typing, as C++ functions only accept signed integers):
painter.drawRect(0.5, 0.5, 5.5, 5.5)
# same as:
painter.drawRect(0, 0, 5, 5)
# so you should use:
painter.drawRect(QtCore.QRectF(0.5, 0.5, 5.5, 5.5))
Finally, while Qt (and Python) sometimes allows transparent usage of both types, in general one or the other is strictly required:
setGeometry(QRect), resize(QSize), etc.);sizeHint(), the SizeHintRole of an item model, rectangles returned by a QStyle subclass or set for a QStyleOption;Whenever you need a conversion from one type to the other, just use the constructor of the floating point class or the to[*] function it provides:
intRect = QtCore.QRect(0, 0, 10, 10)
floatRect = QtCore.QRectF(intRect)
newIntRect = floatRect.toRect()
intTopLeft = floatRect.topLeft().toPoint()
intSize = floatRect.size().toSize()
midRadiusLine = QtCore.QLineF.fromPolar(
intRect.width() * .5, 45).translated(floatRect.center())
intMidRadiusLine = midRadius.toLine()
[1] Be aware that setting angles outside the 0-360 range might give you unexpected results: line.setAngle(361) will result in a line.angle() equal to 0.9999999999999748 due to floating point "[im]precision" and the nature of Pi.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With