QGraphicsEllipseItem 涂画超出边界,留下残留物
如果你有一个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 个回答
这是一个关于QPen的问题。
如果你使用一个宽度更大的QPen(比如1.2),这个问题就会消失(如果我没记错的话,默认情况下,对于连接的地方,QPen会在找到交点时延伸线条)。