何时使用Qt图形浮点类?

3

Qt有一组图形类,分为两个变体:具有整数精度浮点精度
以下是我能记住的。

|    QLine | QLineF    |
| QMargins | QMarginsF |
|   QPoint | QPointF   |
|    QRect | QRectF    |
|    QSize | QSizeF    |

除了显而易见的区别,即一个使用整数,另一个使用浮点数,正如它们的名称和官方文档中所述,我还有很多疑问...
  • 这两种类的使用情况是什么?
  • 是否可以使用比其整数对应物更大的位置和大小?
  • 是否支持分数值?
  • 绘图时是否有任何区别?
  • 如果使用 QLineF 而不是 QLine,图形是否更平滑?

1
是的,您可以使用fp值在子像素边界上定位对象。 - JarMan
好的,现在有点明白了,但是Qt文档对此有些欠缺。 - Jack Lilhammers
1个回答

3
虽然这些类通常可以互换使用并且具有几乎相同的实现,但它们在使用和结果上存在着特殊的差异。
基于整数的类主要用于屏幕坐标(小部件位置、大小等),通常考虑基于像素单位(显然是整数)。
然而,在处理定位/碰撞和绘图时,存在重要的差异。
请考虑以下内容:
>>> 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-1top+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)
# same as:
painter.drawRect(0, 0, 5, 5)
# so you should use:
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]精度"和π的本质所造成的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接