PyQt: Overriding QGraphicsView.drawItems

I need to customize the QGraphicsView drawing process, and so I override the drawItems method as follows:

self.graphicsview.drawItems=self.drawer.drawItems 

where self.graphicsview is a QGraphicsView and self.drawer is a custom class with the drawItems method.
In this method, I check several flags to decide how to draw each element, and then call item.paint , for example:

 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.
However, as soon as it reaches item.paint , it exits the loop - without errors. If I put a legend around the picture, and for each possible type of QGraphicsItem, paste the code that needs to be executed (looking at Qt git-sources), everything will work.
Not a good solution, though ... And I don’t understand how it can even break out of the loop?

+4
source share
2 answers

There is an exception that occurs when items are painted, but not immediately reported. On my system (PyQt 4.5.1, Python 2.6), no exceptions are reported when I deactivate a patch in the following way:

 def drawItems(painter, items, options): print len(items) for idx, i in enumerate(items): print idx, i if idx > 5: raise ValueError() 

Output:

 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> 

However, as soon as I close the application, the following method prints:

 Exception ValueError: ValueError() in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored 

I tried printing threading.currentThread() , but it returns the same thread, regardless of whether it called inside or outside the drawItems method with the monkey.

In your code, this is most likely due to the fact that you are passing options (which is a list of style options objects) to the individual elements, and not to the corresponding option object. Using this code should give the correct results:

 def drawItems(self, painter, items, options): for item, option in zip(items, options): print "Processing", item # ... Do checking ... item.paint(painter, option, self.target) 

Also, you say that self.target is a scene object. The documentation for paint() reads:

This function, which is usually called by QGraphicsView, draws the contents of the element in local coordinates .... The widget argument is optional. If provided, it points to the widget that is drawn; otherwise it is 0. For cached painting, the widget is always 0.

and type QWidget* . QGraphicsScene inherits from QObject and is not widgets, so this is probably wrong too.

However, the fact that the exception is not reported at all or does not immediately suggest some kind of dishonest game, you should contact the attendant.

+3
source

The reason the loop ends abruptly is because an exception is thrown. Python does not process it (there is no try: block), so it is passed to the caller (Qt C ++ code), which has no idea about Python exceptions, so it lost.

Add try / except around the loop and you will see the reason why this happens.

Note. Starting with Python 2.4, you no longer have to override methods in this way.

Instead, you should get a new class from QGraphicsView and add your drawItems() method to this new class. This will correctly replace the original method.

Remember to call super() in the __init__ method! Otherwise, your object will not work properly.

+1
source

All Articles