2009-07-17 6 views
4

J'ai besoin de personnaliser le processus de dessin d'un QGraphicsView, et donc je remplacer la méthode drawItems comme ceci:PyQt: Redéfinition QGraphicsView.drawItems

self.graphicsview.drawItems=self.drawer.drawItems 

self.graphicsview est un QGraphicsView et self.drawer est une classe personnalisée avec une méthode drawItems.
Dans cette méthode, je vérifie quelques drapeaux pour décider comment dessiner chaque élément, puis appelez item.paint, comme ceci:

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

self.target est-QGraphicsScene du QGraphicsView.
Cependant, une fois qu'il atteint item.paint, il sort de la boucle - sans aucune erreur. Si je mets des conditions autour de la peinture, et pour chaque type possible de QGraphicsItem, collez le code qui est supposé être exécuté (en regardant les sources git Qt), tout fonctionne.
Pas une très belle solution cependant ... Et je ne comprends pas comment il pourrait même sortir de la boucle?

+0

J'ai juste essayé d'ajouter cette instruction, 'print item.paint', pour vérifier quelle méthode de peinture serait appelée. Il a imprimé "". Intégré? J'ai également un objet personnalisé dérivé de QGraphicsItem, et l'instruction ci-dessus donne "bound method of ..." à la place. Que signifie cette différence? – carlpett

+0

"built-in" signifie que le code compilé dans la bibliothèque Qt est appelé alors que "méthode liée" signifie que le code Python est appelé. –

Répondre

3

Une exception se produit lorsque les éléments sont peints, mais elle n'est pas signalée immédiatement. Sur mon système (PyQt 4.5.1, Python 2.6), pas d'exception est signalée lorsque je singe patch la méthode suivante:

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

Sortie:

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> 

Cependant, une fois que je ferme l'application, la méthode suivante est imprimé:

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

J'ai essayé l'impression threading.currentThread(), mais il renvoie le même fil si on l'appelle l'intérieur ou à l'extérieur de la méthode de singe patché drawItems.

Dans votre code, cela est probablement dû au fait que vous transmettez options (qui est une liste d'objets d'options de style) aux éléments individuels plutôt qu'à l'objet d'option correspondant. En utilisant ce code devrait vous donner les bons résultats:

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

, vous dites également le self.target est l'objet de la scène.Le documentation for paint() dit:

Cette fonction, généralement appelée par QGraphicsView, peint le contenu d'un élément en coordonnées locales. ... L'argument du widget est optionnel. Si fourni, il pointe vers le widget en cours de peinture; sinon, il est 0. Pour la peinture en cache, le widget est toujours 0.

et le type est QWidget*. QGraphicsScene hérite de QObject et n'est pas un widget, il est donc probable que ce soit faux, aussi.

Néanmoins, le fait que l'exception ne soit pas du tout signalée ou pas tout de suite suggère un jeu déloyal, vous devez contacter le responsable.

+0

Hm. Je ne reçois pas cette erreur de thread. Cependant, j'obtiens "l'argument 2 de QGraphicsPolygonItem.paint() a un type invalide". L'argument 2 est le paramètre d'option, qui est passé inchangé. Faire 'type (options)' m'indique qu'il s'agit d'une liste Python standard - donc il est descendu, mais ne peut pas être "up-cast" à nouveau. Cela doit être un bug dans les wrappers? – carlpett

+0

Il suffit de relire les docs et joué autour d'un peu et réalisé la même chose (re la liste des options). Merci de votre aide! Il est bizarre que l'exception ne semble pas remonter à moins que je l'entoure d'un essai/sauf si ... – carlpett

1

La raison pour laquelle la boucle se termine soudainement est qu'une exception est levée. Python ne le gère pas (il n'y a pas de bloc try:), donc il est passé à l'appelé (le code C++ de Qt) qui n'a aucune idée des exceptions Python, donc c'est perdu. Ajouter un essai/sauf autour de la boucle et vous devriez voir la raison pour laquelle cela se produit.

Remarque: Depuis Python 2.4, vous ne devez plus surcharger les méthodes de cette façon. Au lieu de cela, vous devez dériver une nouvelle classe à partir de QGraphicsView et ajouter votre méthode drawItems() à cette nouvelle classe. Cela remplacera la méthode originale correctement. N'oubliez pas d'appeler super() dans la méthode __init__! Sinon, votre objet ne fonctionnera pas correctement.

+0

Mais ... Ma méthode prioritaire est appelée correctement? – carlpett

+0

C'est plus par hasard que par intention. –

+0

Non, le dépassement fonctionne définitivement, je viens de le tester. –