QGraphicsEllipseItem 涂画超出边界,留下残留物

2 投票
1 回答
1027 浏览
提问于 2025-04-17 17:59

如果你有一个QGraphicsEllipseItem,它的宽度远大于高度(也就是扁平的),那么它在绘制的时候会超出自己的边界。这就意味着它绘制得不太正确,当你拖动它的时候,屏幕上会留下残影。下面的代码可以复现这个问题(对不懂Python的人表示抱歉,但对C++的朋友应该能理解):

import sys
from PySide import QtCore, QtGui

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    scene = QtGui.QGraphicsScene()
    scene.setSceneRect(0, 0, 400, 400)
    ellipse = QtGui.QGraphicsEllipseItem(QtCore.QRectF(0, 0, 320, 5))
    ellipse.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
    ellipse.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
    ellipse.setPos(40, 200)
    ellipse.setPen(QtGui.QPen(QtCore.Qt.red, 1))
    scene.addItem(ellipse)
    view = QtGui.QGraphicsView(scene)
    view.show()
    sys.exit(app.exec_())

关键点是这个QGraphicsEllipseItem的宽度是320,而高度只有5。如果你选择了这个椭圆,选择框的虚线会显示在这个物体的边界上,你会发现椭圆的左右边缘超出了这个边界。如果你拖动这个物体,就会出现残影。

这是在Windows 7 64位系统上,使用的是PySide 1.1.2,如果这有影响的话。

如果你开启抗锯齿(比如用view.setRenderHint(QtGui.QPainter.Antialiasing)),椭圆就会在它的边界内绘制,这样一切就正常了。

我希望能有选择绘制普通的或抗锯齿的选项,但如果没有更好的解决办法,我可以一直使用抗锯齿的方式。为了处理这个问题,我创建了QGraphicsEllipseItem的子类,并在基类的边界矩形周围加了很多填充,比如:

def boundingRect(self):
    return QGraphicsEllipseItem.boundingRect(self).adjusted(-40, -40, 40, 40)

这样在很多情况下可以解决问题,但如果椭圆非常大,可能会超出边界很远,所以很难知道该加多少填充。而且这种方法并不太好,因为这意味着我的边界在大多数情况下都离得很远(这对碰撞检测等有影响)。

你也可以通过改变视图的更新模式来避免残影,比如:

view.setViewportUpdateMode(QtGui.QGraphicsView.FullViewportUpdate)

为了处理一个特定类型的图形物体的绘制问题,居然需要这样做,感觉有点可悲……

我想我可以尝试在我自己的QGraphicsEllipseItem子类中“正确”地绘制这个椭圆,但我怀疑基类只是告诉绘图工具去画一个椭圆,所以我得费很多劲来想出一个不使用绘图工具的椭圆绘制算法……

还有其他想法吗?看起来最不糟糕的选择是什么?我倾向于开启FullViewportUpdate。

1 个回答

3

这是一个关于QPen的问题。

如果你使用一个宽度更大的QPen(比如1.2),这个问题就会消失(如果我没记错的话,默认情况下,对于连接的地方,QPen会在找到交点时延伸线条)。

撰写回答