2010-03-15 7 views
11

Cela m'a embêté pendant plus de deux jours maintenant, donc j'ai pensé que je devrais demander. J'utilise Qt 4.5.3 (compilé avec VC2008) sur Win7.QGraphicsView et eventFilter

J'ai les classes MyGraphicsView (hérite de QGraphicsView) et MyFilter (hérite de QObject).

Quand j'installer l'objet MyFilter comme filtre d'événement à MyGraphicsView, les événements souris sont livrés à MyFilter après ils sont livrés à MyGraphicsView alors que les événements clés sont livrés à MyFilter avant qu'ils sont livrés à MyGraphicsView.

Dans le second cas, j'installer l'objet MyFilter comme (ce qui est un QGLWidget standart) filtre d'événements à MyGraphicsView-> viewport(), les événements de souris sont livrés à MyFilter avant qu'ils sont livrés à MyGraphicsView, alors que la clé les événements sont livrés au seulement MyGraphicsView.

Les événements sont censés être envoyés aux filtres d'événements avant qu'ils ne soient remis à l'objet réel, alors pourquoi cela se produit-il? Que dois-je faire pour assurer cette commande?

Merci d'avance. Cordialement.

+1

Depuis l'ordet semble être le problème, peut-être un extrait de votre code serait utile. – gregseth

+0

OK Les gars, voici le lien vers le code minimal qui reproduit le problème. http://rapidshare.com/files/363574158/QGVEF.rar – erelender

Répondre

12

QGraphicsView est une sous-classe de QAbstractScrollArea qui est la cause de ces comportements.

Dans le premier cas, QAbstractScrollArea s'ajoute comme un filtre d'événement à MyGraphicsView lorsque setViewport() est appelé. Le filtre d'événements de QAbstractScrollArea capture l'événement de la souris, l'envoie d'abord via viewportEvent(), puis à la gestion des événements QWidget qui se propage aux gestionnaires d'événements de la souris MyGraphicsView. Ce n'est qu'après que le filtre d'événements de QAbstractScrollArea est terminé et que MyFilter s'exécute. Dans le second cas, les événements clés sont uniquement transmis à MyGraphicsView, car dans setViewport(), QAbstractScrollArea se définit comme le proxy de mise au point. Si le proxy de mise à jour est réinitialisé avec le code suivant, les événements clés seront livrés.

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

Une alternative est d'installer le filtre d'événement à la fois la vue graphique et sa fenêtre, mais modifier le filtre pour traiter uniquement les événements clés d'un événement de l'objet et de la souris de l'autre.

changement MyFilter.h

QObject *keyObj; 
    QObject *mouseObj; 

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

changement MyFilter.cpp

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

et

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"; 
} 

changement 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

En fait, c'est ce que je fais en ce moment mais je pense que c'est plutôt une solution de contournement, pas une solution. Mes filtres d'événements proviennent de plugins et je ne pense pas que la gestion du filtrage d'événements basé sur un objet soit leur préoccupation. Néanmoins, merci pour l'explication de la raison pour laquelle cela se produit. – erelender

+0

Bien que je pense que mon explication précédente était généralement correcte, je pense que c'est maintenant une meilleure explication. Si vous ne vous souciez pas de la gestion des événements clés de la zone de défilement (page précédente, page suivante, etc.), l'installation du filtre d'événements sur la fenêtre d'affichage et la suppression de son proxy de mise au point est une solution plus simple. Sinon, l'installation du filtre d'événements sur MyGraphicsView et viewport est probablement préférable. – baysmith

+0

Vous avez raison, votre solution précédente pourrait être plus adaptée à un usage général. Dans mon cas, j'essaie de faire quelque chose avec Qt & OSG, c'est pourquoi la plupart de mes problèmes ne sont pas résolus :). Cette solution correspond à mon cas comme un gant, merci. Mais pour des raisons de référence future, pouvez-vous poster votre ancienne solution comme une autre réponse afin que les autres puissent la voir? Il est accessible via le lien "edit: ... ago". – erelender

-2

Que diriez-vous d'essayer de ne pas utiliser le filtre, mais réimplémentez gestionnaires d'QEvent nécessaires à MyGraphicsView comme ici:

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

Je le fais déjà. Mais le sous-classement et le filtrage d'événements sont à des fins différentes et non interchangeables dans mon cas. – erelender

+1

OK, si vous avez vraiment besoin d'un filtrage d'événements, il peut y avoir un problème avec la valeur true/false incorrecte retournée par la méthode eventFilter(), assurez-vous que ce n'est pas le cas pour vous. Aussi, je télécharge un projet de test sur http://uploading.com/files/7c7adam5/graphicsview.zip/ qui gère les événements comme supposé. Il a été compilé sur Slackware Linux avec la version git actuelle de Qt. Donc, si ce projet de test ne fonctionne pas avec votre version de Qt (4.5.3), cela peut être un problème avec Qt qui est déjà résolu, mais ce n'est pas un cas pour moi. En outre, il peut être "fonction" dépendant de la plate-forme. Bonne chance! –

+0

Votre exemple fonctionne également bien avec Qt 4.5.3 car ce n'est pas le même cas que le mien. Dans votre exemple, graphicsview sous-classe QWidget, pas QGraphicsView. Aussi le filtre d'événement est installé sur graphicsview (sous-classe de QWidget), pas sur QGraphicsView, j'ai posté l'exemple de code qui reproduit le problème. Si vous y jetez un coup d'oeil, vous comprendrez mieux mon problème. – erelender