2010-03-15 14 views
11

Questo mi ha infastidito per più di due giorni, quindi ho pensato di doverlo chiedere. Sto usando Qt 4.5.3 (compilato con VC2008) su Win7.QGraphicsView ed eventFilter

I have MyGraphicsView (eredita QGraphicsView) e MyFilter (eredita QObject) classi.

quando installo l'oggetto myFilter come un filtro eventi per MyGraphicsView, gli eventi del mouse vengono consegnati al myFilter dopo di essere consegnati al MyGraphicsView mentre gli eventi chiave sono consegnati al myFilter prima di essere consegnati al MyGraphicsView.

Nel secondo caso, i installare l'oggetto myFilter come un filtro eventi per MyGraphicsView-> finestra() (che è una QGLWidget standart), eventi mouse vengono consegnati myFilter prima essere consegnati al MyGraphicsView, mentre Key gli eventi vengono consegnati a solo MyGraphicsView.

Gli eventi dovrebbero essere consegnati ai filtri eventi prima che vengano consegnati all'oggetto reale, quindi perché sta succedendo? Cosa dovrei fare per garantire questo ordine?

Grazie in anticipo. I migliori saluti.

+1

Dal momento che il problema sembra essere il problema, potrebbe essere uno snippet del tuo codice sarebbe utile. – gregseth

+0

OK Ragazzi, ecco il link al codice minimale che riproduce il problema. http://rapidshare.com/files/363574158/QGVEF.rar – erelender

risposta

12

QGraphicsView è una sottoclasse di QAbstractScrollArea che è la causa di questi comportamenti.

Nel primo caso, QAbstractScrollArea si aggiunge come filtro eventi a MyGraphicsView quando viene chiamato setViewport(). Il filtro eventi di QAbstractScrollArea cattura l'evento del mouse, lo invia prima tramite viewportEvent() e quindi alla gestione degli eventi QWidget che si propaga ai gestori di eventi del mouse MyGraphicsView. Solo dopo questo è finito il filtro degli eventi di QAbstractScrollArea e MyFilter può essere eseguito.

Nel secondo caso, gli eventi chiave vengono inviati solo a MyGraphicsView poiché in setViewport() QAbstractScrollArea si imposta come proxy di attivazione. Se il proxy di attivazione viene reimpostato con il seguente codice, gli eventi chiave verranno consegnati.

w.viewport()->setFocusProxy(0); 

Un'alternativa è quella di installare il filtro evento sia la vista grafica e la sua finestra, ma modificare il filtro per eventi chiave elaborare solo da un oggetto e mouse eventi dall'altro.

Change MyFilter.h

QObject *keyObj; 
    QObject *mouseObj; 

public: 
    MyFilter(QObject *keyObj, QObject *mouseObj, QObject *parent = NULL); 

Change MyFilter.cpp

MyFilter::MyFilter(QObject *keyObj, QObject *mouseObj, QObject *parent /*= NULL*/) : QObject(parent), keyObj(keyObj), mouseObj(mouseObj) 

e

if (obj == keyObj && e->type() == QEvent::KeyPress) 
{ 
    qDebug()<<"Key Event recieved by MyFilter"; 
} 
else if (obj == mouseObj && e->type() == QEvent::MouseButtonPress) 
{ 
    qDebug()<<"Mouse Event recieved by MyFilter"; 
} 

Change main.cpp

MyFilter *filter = new MyFilter(&w, w.viewport(), &w); 

// Use this line to install to the viewport 
w.viewport()->installEventFilter(filter); 

//Use this line to install to MyGraphicsView 
w.installEventFilter(filter); 
+0

In realtà, questo è quello che sto facendo in questo momento, ma penso che sia più come una soluzione alternativa, non una soluzione. I miei filtri evento provengono da plugin e non penso che la gestione del filtro degli eventi basato sugli oggetti dovrebbe essere la loro preoccupazione. Tuttavia, grazie per la spiegazione del perché questo sta accadendo. – erelender

+0

Anche se penso che la mia precedente spiegazione fosse generalmente corretta, penso che ora sia una spiegazione migliore. Se non ti interessa la gestione degli eventi chiave dell'area di scorrimento (pagina su, pagina giù, ecc.), Installare il filtro eventi sul viewport e svuotare il proxy di attivazione è una soluzione più semplice. Altrimenti, installare il filtro eventi sia su MyGraphicsView che su viewport è probabilmente migliore. – baysmith

+0

Hai ragione, la tua soluzione precedente potrebbe essere più adatta all'uso generale. Nel mio caso, sto provando a fare alcune cose fantasiose con Qt e OSG, motivo per cui molti dei miei problemi rimangono irrisolti :). Questa soluzione si adatta al mio caso come un guanto, grazie. Ma per riferimento futuro, puoi pubblicare la tua vecchia soluzione come un'altra risposta in modo che gli altri possano vederla? È accessibile tramite il link "modificato: ... fa". – erelender

-2

ne cercare di non utilizzare il filtro, ma reimplementare necessari gestori QEvent a MyGraphicsView come qui:

void MyGraphicsView::mousePressEvent(QMouseEvent* pe) 
{ 
if (pe->buttons() & Qt::LeftButton) 
{ 
    this->setCursor(Qt::CrossCursor); 
    zoomOrigin = pe->pos(); 
    rubberBand = new QRubberBand(QRubberBand::Rectangle, this); 
    rubberBand->setGeometry(QRect(zoomOrigin, QSize(0,0))); 
    rubberBand->show(); 
} 
if (pe->buttons() & Qt::MidButton) 
{ 
    panOrigin = pe->pos(); 
     this->setCursor(Qt::ClosedHandCursor); 
} 
} 
+0

Lo faccio già. Ma la sottoclassi e il filtraggio degli eventi sono per scopi diversi e non sono intercambiabili nel mio caso. – erelender

+1

OK, se hai veramente bisogno del filtraggio degli eventi potrebbe esserci un problema con valori errati vero/falso restituiti dal metodo eventFilter(), assicurati che non sia un caso per te. Inoltre, carica il progetto di test su http://uploading.com/files/7c7adam5/graphicsview.zip/ che gestisce gli eventi come supposto. È stato compilato su Slackware Linux con l'attuale versione git di Qt. Quindi, se questo progetto di test non funziona con la versione Qt (4.5.3), può essere un problema con Qt già risolto, ma non mi sembra un caso. Inoltre può essere una "funzione" dipendente dalla piattaforma. In bocca al lupo! –

+0

Anche il tuo esempio funziona bene con Qt 4.5.3 perché non è lo stesso del mio. Nel tuo esempio, graphicsview sottoclasse QWidget, non QGraphicsView. Anche il filtro eventi è installato su graphicsview (sottoclasse di QWidget), non su QGraphicsView, ho postato il codice di esempio che riproduce il problema. Se dai un'occhiata, capirai meglio il mio problema. – erelender