PyQt:重写QGraphicsView.drawItems
我需要自定义一个QGraphicsView的绘图过程,所以我像这样重写了drawItems方法:
self.graphicsview.drawItems=self.drawer.drawItems
这里的self.graphicsview
是一个QGraphicsView,而self.drawer
是一个自定义的类,里面有一个drawItems
的方法。
在这个方法里,我检查了一些标志,以决定如何绘制每个项目,然后调用item.paint
,像这样:
def drawItems(self, painter, items, options):
for item in items:
print "Processing", item
# ... Do checking ...
item.paint(painter, options, self.target)
self.target
是QGraphicsView的QGraphicsScene。
但是,一旦执行到item.paint
,它就会跳出循环——没有任何错误。如果我在绘制的地方加上条件判断,并且针对每种可能的QGraphicsItem类型粘贴应该执行的代码(通过查看Qt的源代码),一切就正常工作了。
不过,这样的解决方案并不好……我也不明白它怎么会跳出循环?
2 个回答
循环突然结束的原因是抛出了一个异常。Python没有处理这个异常(因为没有用到try:
块),所以这个异常就传递给了调用的部分(Qt的C++代码),而C++代码对Python的异常一无所知,因此这个异常就消失了。
在循环周围加上一个try/except块,你就能看到发生这个问题的原因了。
注意:从Python 2.4开始,不应该再这样重写方法了。
相反,你需要从QGraphicsView派生一个新类,并在这个新类中添加你的drawItems()
方法。这样才能正确替换掉原来的方法。
别忘了在__init__
方法中调用super()
!否则,你的对象就无法正常工作。
在绘制项目时会出现一个异常,但并不会立即报告。在我的系统上(PyQt 4.5.1,Python 2.6),当我修改以下方法时,并没有报告任何异常:
def drawItems(painter, items, options):
print len(items)
for idx, i in enumerate(items):
print idx, i
if idx > 5:
raise ValueError()
输出:
45
0 <PyQt4.QtGui.QGraphicsPathItem object at 0x3585270>
1 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356ca68>
2 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356ce20>
3 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356cc88>
4 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356cc00>
5 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356caf0>
6 <PyQt4.QtGui.QGraphicsSimpleTextItem object at 0x356cb78>
不过,一旦我关闭应用程序,就会打印出以下方法:
Exception ValueError: ValueError() in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
我尝试打印 threading.currentThread()
,但无论是在修改过的 drawItems
方法内还是外部调用,它返回的都是同一个线程。
在你的代码中,这可能是因为你把 options
(这是一个样式选项对象的列表)传给了每个单独的项目,而不是相应的选项对象。使用以下代码应该能给你正确的结果:
def drawItems(self, painter, items, options):
for item, option in zip(items, options):
print "Processing", item
# ... Do checking ...
item.paint(painter, option, self.target)
另外,你提到 self.target
是场景对象。关于 paint()
的文档中说:
这个函数通常由 QGraphicsView 调用,用于在本地坐标中绘制项目的内容。... widget 参数是可选的。如果提供,它指向正在绘制的窗口部件;否则,它是 0。对于缓存绘制,widget 始终是 0。
而且类型是 QWidget*
。QGraphicsScene
继承自 QObject
,并不是一个窗口部件,所以这可能也是错误的。
不过,异常根本没有报告,或者没有立即报告,这表明可能有问题,你应该联系维护者。