虽然这些类通常可以互换使用并且具有几乎相同的实现,但它们在使用和结果上存在着特殊的差异。
基于整数的类主要用于屏幕坐标(小部件位置、大小等),通常考虑基于像素单位(显然是整数)。
然而,在处理定位/碰撞和绘图时,存在重要的差异。
请考虑以下内容:
>>> 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
这是因为QRect仅考虑整数(“像素”)大小,而显然(1,1)在“另一个像素”上。对于
right()
和
bottom()
函数,QRect也很奇特,因为它们总是出于历史原因返回
left+width-1
和
top+height-1
,正如文档中所解释的那样。
>>> r = QtCore.QRect(0, 0, 1, 1)
>>> print(r.right())
0
因此,请始终记住,对于这些坐标的设置者(set*
和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)
浮点数类还具有整数类不可用的功能(主要是因为实现它们可能/有用/合理)。例如,QLineF类:
- 可以返回与另一个QLineF的交点(或其延伸的交点);
- 具有获取和设置线本身的角度(从其
p1
起始点),或者与另一条线创建的角度(或者更好的是它们的延伸,如果它们不相交)[1];
- 可以从极坐标创建,给定长度和角度;
浮点数类允许更精确的绘制和定位,这在需要抗锯齿绘制或处理基于比例值的内容时是重要的方面(考虑放大的QGraphicsScene或文本显示,因为字体是矢量基础的)。例如,以下将给出非常不同的结果:
painter.setRenderHints(painter.Antialiasing)
painter.drawRect(QtCore.QRect(1, 1, 2, 2))
painter.drawRect(QtCore.QRectF(1, 1, 2.5, 2.5))
然后,需要记住的是,QPainter 的所有接受数字值作为主要参数的
简单 绘图函数将始终使用整数值(我认为这是由于 Python 的动态类型,因为 C++ 函数只接受有符号整数):
painter.drawRect(0.5, 0.5, 5.5, 5.5)
painter.drawRect(0, 0, 5, 5)
painter.drawRect(QtCore.QRectF(0.5, 0.5, 5.5, 5.5))
最后,虽然Qt(和Python)有时允许透明地使用两种类型,但通常情况下必须严格要求其中一种类型:
- 所有与小部件几何相关的函数仅接受整数类(
setGeometry(QRect)
,resize(QSize)
等);
- 对于必须返回几何值的函数重载,例如
sizeHint()
,项目模型的SizeHintRole
,由QStyle子类返回或设置的矩形,也是如此;
- QRegion仅能接受QPolygon和QRect,因为它是一个像素映射对象;
- QGraphicsRectItem、QGraphicsEllipseItem和QGraphicsPolygonItem只允许在其构造函数或设置器中使用浮点类;
- 复杂的构造函数使用其精度类型的类(QRect不会接受QPointF或QSizeF等);
- 所有映射QGraphicsScene坐标的函数在将场景映射到整数类时必须使用,在从场景映射时必须使用浮点数。
每当您需要从一种类型转换为另一种类型时,只需使用浮点类的构造函数或其提供的to[*]
函数:
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]请注意,设置在0-360范围之外的角度可能会给您带来意想不到的结果:line.setAngle(361)
将导致line.angle()
等于0.9999999999999748,这是由于浮点数"[im]精度"和π的本质所造成的。