计算 boundingRect 的 QGraphicsPathItem 问题
QGraphicsPathItem issue with computing boundingRect
我对 Qt5
(PySide2
) 和 Qt4
(PySide
) 之间的行为差异感到困惑。我觉得 Qt5
有一个错误,但也许我做错了什么?
简而言之:将计算的 QPainterPath
应用于 QGraphicsPathItem
(使用 setPath
)时,QGraphicsPathItem
的结果大小 更大 比 QPainterPath
本身的大小高 1.5 个像素。这对我来说毫无意义,而且对于 Qt4 来说大小是完全一样的。
我提供了一段简单的代码来用 PySide 和 PySide2 重现。
使用 PySide:
#!/usr/bin/env python2
from PySide.QtCore import *
from PySide.QtGui import *
class Foo (QGraphicsPathItem):
def __init__(self, parent):
super(Foo, self).__init__()
path = QPainterPath()
path.addRect(0,0,10,10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x=Foo(None)
结果是:
$ python2 ./with_py2.py
PySide.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
大小相同,符合预期。一切顺利。
与Qt5完全相同的代码:
#!/usr/bin/env python3
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Foo (QGraphicsPathItem):
def __init__(self, parent):
super(Foo, self).__init__()
path = QPainterPath()
path.addRect(0,0,10,10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x=Foo(None)
结果:
$ python3 bug.py
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide2.QtCore.QRectF(-0.500000, -0.500000, 11.000000, 11.000000)
有人看到任何明显的解释吗?
谢谢
boundingRect 依赖于 QGraphicsPathItem 的 QPen 来计算它,如源代码所示。
Qt4:
QRectF QGraphicsPathItem::boundingRect() const
{
Q_D(const QGraphicsPathItem);
if (d->boundingRect.isNull()) {
qreal pw = pen().widthF();
if (pw == 0.0)
d->boundingRect = d->path.controlPointRect();
else {
d->boundingRect = shape().controlPointRect();
}
}
return d->boundingRect;
}
QRectF QGraphicsPathItem::boundingRect() const
{
Q_D(const QGraphicsPathItem);
if (d->boundingRect.isNull()) {
qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
if (pw == 0.0)
d->boundingRect = d->path.controlPointRect();
else {
d->boundingRect = shape().controlPointRect();
}
}
return d->boundingRect;
}
如果您查看两个版本的 Qt 文档,您会发现默认创建的 QPen 的值发生了变化:
- Qt4:
The default pen is a solid black brush with 0 width, square cap style
(Qt::SquareCap), and bevel join style (Qt::BevelJoin).
(强调我的)
- Qt5:
The default pen is a solid black brush with 1 width, square cap style
(Qt::SquareCap), and bevel join style (Qt::BevelJoin).
(强调我的)
如果您想观察 PySide2 中的 PySide 行为,请将 QPen(Qt::NoPen)
设置为 QGraphicsPathItem
:
class Foo(QGraphicsPathItem):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setPen(QPen(Qt.NoPen))
path = QPainterPath()
path.addRect(0, 0, 10, 10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x = Foo()
输出
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
我对 Qt5
(PySide2
) 和 Qt4
(PySide
) 之间的行为差异感到困惑。我觉得 Qt5
有一个错误,但也许我做错了什么?
简而言之:将计算的 QPainterPath
应用于 QGraphicsPathItem
(使用 setPath
)时,QGraphicsPathItem
的结果大小 更大 比 QPainterPath
本身的大小高 1.5 个像素。这对我来说毫无意义,而且对于 Qt4 来说大小是完全一样的。
我提供了一段简单的代码来用 PySide 和 PySide2 重现。
使用 PySide:
#!/usr/bin/env python2
from PySide.QtCore import *
from PySide.QtGui import *
class Foo (QGraphicsPathItem):
def __init__(self, parent):
super(Foo, self).__init__()
path = QPainterPath()
path.addRect(0,0,10,10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x=Foo(None)
结果是:
$ python2 ./with_py2.py
PySide.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
大小相同,符合预期。一切顺利。
与Qt5完全相同的代码:
#!/usr/bin/env python3
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Foo (QGraphicsPathItem):
def __init__(self, parent):
super(Foo, self).__init__()
path = QPainterPath()
path.addRect(0,0,10,10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x=Foo(None)
结果:
$ python3 bug.py
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide2.QtCore.QRectF(-0.500000, -0.500000, 11.000000, 11.000000)
有人看到任何明显的解释吗?
谢谢
boundingRect 依赖于 QGraphicsPathItem 的 QPen 来计算它,如源代码所示。
Qt4:
QRectF QGraphicsPathItem::boundingRect() const
{
Q_D(const QGraphicsPathItem);
if (d->boundingRect.isNull()) {
qreal pw = pen().widthF();
if (pw == 0.0)
d->boundingRect = d->path.controlPointRect();
else {
d->boundingRect = shape().controlPointRect();
}
}
return d->boundingRect;
}
QRectF QGraphicsPathItem::boundingRect() const
{
Q_D(const QGraphicsPathItem);
if (d->boundingRect.isNull()) {
qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
if (pw == 0.0)
d->boundingRect = d->path.controlPointRect();
else {
d->boundingRect = shape().controlPointRect();
}
}
return d->boundingRect;
}
如果您查看两个版本的 Qt 文档,您会发现默认创建的 QPen 的值发生了变化:
- Qt4:
The default pen is a solid black brush with 0 width, square cap style (Qt::SquareCap), and bevel join style (Qt::BevelJoin).
(强调我的)
- Qt5:
The default pen is a solid black brush with 1 width, square cap style (Qt::SquareCap), and bevel join style (Qt::BevelJoin).
(强调我的)
如果您想观察 PySide2 中的 PySide 行为,请将 QPen(Qt::NoPen)
设置为 QGraphicsPathItem
:
class Foo(QGraphicsPathItem):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setPen(QPen(Qt.NoPen))
path = QPainterPath()
path.addRect(0, 0, 10, 10)
print(str(path.boundingRect()))
self.setPath(path)
print(str(self.boundingRect()))
x = Foo()
输出
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)
PySide2.QtCore.QRectF(0.000000, 0.000000, 10.000000, 10.000000)