QGraphicsView and eventFilter
Asked Answered
H

2

11

This has been bugging me for more than two days now, so i thought i should ask. I am using Qt 4.5.3 (compiled with VC2008) on Win7.

I have MyGraphicsView (inherits QGraphicsView) and MyFilter (inherits QObject) classes.

When i install the MyFilter object as an event filter to MyGraphicsView, Mouse events are delivered to MyFilter after they are delivered to MyGraphicsView whereas Key events are delivered to MyFilter before they are delivered to MyGraphicsView.

In the second case, i install the MyFilter object as an event filter to MyGraphicsView->viewport() (which is a standart QGLWidget), Mouse events are delivered to MyFilter before they are delivered to MyGraphicsView, whereas Key events are delivered to only MyGraphicsView.

The events are supposed to be delivered to event filters before they are delivered to the actual object, so why is this happening? What should i do to ensure this order?

Thanks in advance. Best Regards.

Helbona answered 15/3, 2010 at 9:12 Comment(2)
Since the ordet seems to be the issue, may be a snippet of your code would be useful.Broaddus
OK Guys, here is the link to the minimal code that reproduces the problem. rapidshare.com/files/363574158/QGVEF.rarHelbona
M
13

QGraphicsView is a subclass of QAbstractScrollArea which is the cause of these behaviors.

In the first case, the QAbstractScrollArea adds itself as a event filter to the MyGraphicsView when setViewport() is called. The QAbstractScrollArea's event filter captures the mouse event, first sends it through viewportEvent(), and then to the QWidget event handling which propagates to the MyGraphicsView mouse event handlers. Only after this is the QAbstractScrollArea's event filter finished and MyFilter gets to run.

In the second case, key events are delivered only to the MyGraphicsView because in setViewport() the QAbstractScrollArea sets itself as the focus proxy. If the focus proxy is reset with the following code, the key events will be delivered.

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

An alternative is to install the event filter on both the graphics view and its viewport, but modify the filter to only process key events from one object and mouse events from the other.

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)

and

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);
Muth answered 23/3, 2010 at 16:1 Comment(5)
Actually, this is what i am doing right now but i think it is more like a workaround, not a solution. My event filters are coming from plugins and i don't think handling the object based event filtering should be their concern. Nevertheless, thanks for the explanation to why this is happening.Helbona
Although I think my previous explanation was generally correct, I think this is now a better explanation. If you don't care about the key event handling of the scroll area (page up, page down, etc.), then installing the event filter on the viewport and clearing its focus proxy is a simpler solution. Otherwise, installing the event filter on both the MyGraphicsView and viewport is probably better.Muth
You are right, your previous solution might be more suitable for general use. In my case, i am trying to do some fancy stuff with Qt & OSG, which is why most of my problems go unsolved :). This solution fits my case like a glove, thank you. But for the sake of future reference, can you post your old solution as another answer so that others can see it? It is accessible via the "edited: ... ago" link.Helbona
As requested, the first solution has been appended as an alternative solution.Muth
Trying to add this over here as well but in what function is that if(obj== part ? I'm bit lost...Checkmate
S
-2

How about to try not using filter but reimplement necessary QEvent handlers at MyGraphicsView like here:

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);
}
}
Stratiform answered 19/3, 2010 at 8:19 Comment(4)
I already do that. But subclassing and event filtering are for different purposes and non-interchangeable in my case.Helbona
OK, if you really need event filtering there may be a problem with incorrect true/false-value returned by eventFilter() method, make sure that it isn't a case for you. Also I upload test project to uploading.com/files/7c7adam5/graphicsview.zip that handle events as supposed. It has been compiled on Slackware Linux with current git-version of Qt. So if this test project will not work with your Qt version (4.5.3) it can be a problem with Qt that is fixed already, but it isn't look as a case to me. Also it can be platform dependent "feature". Good luck!Stratiform
Your example also works fine with Qt 4.5.3 because it is not the same case as mine. In your example, graphicsview subclasses QWidget, not QGraphicsView. Also the event filter is installed on graphicsview (subclass of QWidget), not on QGraphicsView, I posted the sample code that reproduces the problem. If you take a look at it, you will understand my problem better.Helbona
Yeah you are right, miss that, sorry. Have looked at your project and have investigate that if you move scene creating, setting viewport and both (uncomment second) filters to MyGraphicsView's constructor app'll work as supposed, try to realize why now.Stratiform

© 2022 - 2024 — McMap. All rights reserved.