PyQt: Sostituzione di QGraphicsView.drawItems
Domanda
Ho bisogno di personalizzare il processo disegno di un QGraphicsView, e così sovrascrivo metodo come questo i drawItems:
self.graphicsview.drawItems=self.drawer.drawItems
dove self.graphicsview
è un QGraphicsView, e self.drawer
è una classe personalizzata con un metodo drawItems
.
In questo metodo verifico un paio di bandiere per decidere come disegnare ogni elemento, e quindi chiamare item.paint
, in questo modo:
def drawItems(self, painter, items, options):
for item in items:
print "Processing", item
# ... Do checking ...
item.paint(painter, options, self.target)
self.target
è QGraphicsScene del QGraphicsView.
Tuttavia, una volta che raggiunge item.paint
, si rompe fuori dal giro - senza errori. Se metto i condizionali intorno alla pittura, e per ogni possibile tipo di QGraphicsItem incolla il codice che dovrebbe essere eseguito (guardando le Qt git-sources), tutto funziona.
Non una soluzione molto elegante anche se ... E io non capisco come si potrebbe anche spezzare il ciclo?
Soluzione
C'è un'eccezione che si verifica quando gli elementi sono verniciati, ma non è segnalato subito. Sul mio sistema (PyQt 4.5.1, Python 2.6), non fa eccezione viene segnalato quando ho scimmia-patch il seguente metodo:
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>
Tuttavia, una volta che chiudo l'applicazione, il metodo seguente è stampata:
Exception ValueError: ValueError() in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
ho provato la stampa threading.currentThread()
, ma restituisce lo stesso filo se si chiama in- o fuori del metodo drawItems
scimmia-patched.
Nel codice, questo è probabilmente dovuto al fatto che si passa options
(che è un elenco di opzioni di stile oggetti) per le singole voci, piuttosto che il rispettivo oggetto dell'opzione. Utilizzando questo codice dovrebbe dare i risultati corretti:
def drawItems(self, painter, items, options):
for item, option in zip(items, options):
print "Processing", item
# ... Do checking ...
item.paint(painter, option, self.target)
Inoltre, si dice il self.target
è l'oggetto di scena. Il per paint()
dice:
Questa funzione, che di solito è chiamato da QGraphicsView, vernici il contenuto di un elemento in coordinate locali. ... L'argomento widget è facoltativa. Se previsto, indica al widget che viene dipinto su; in caso contrario, è 0. Per la pittura nella cache, widget è sempre 0.
e il tipo è QWidget*
. QGraphicsScene
eredita da QObject
e non è un widget, quindi è probabile che questo è sbagliato, troppo.
Ancora, il fatto che l'eccezione non viene segnalato a tutti, o non subito suggerisce qualche fallo di gioco, è necessario contattare il manutentore.
Altri suggerimenti
Il motivo per cui il ciclo esce improvvisamente è che viene generata un'eccezione. Python non gestisce essa (non v'è alcun blocco try:
), quindi è passato alla chiamata (codice di Qt C ++), che non ha alcuna idea sulle eccezioni Python, quindi è perso.
Aggiungi un try / tranne in tutto il ciclo e si dovrebbe vedere il motivo per cui questo accade.
. Nota: Dal momento che Python 2.4, non si deve sostituire i metodi in questo modo più
Al contrario, è necessario derivare una nuova classe da QGraphicsView e aggiungere il metodo drawItems()
a questa nuova classe. Questo sostituirà correttamente il metodo originale.
Non dimenticare di chiamare super()
nel metodo __init__
! In caso contrario, l'oggetto non funziona correttamente.