views:

536

answers:

2

Hello everyone,

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.

A: 

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);
}
}
Yuriy Zhyromskiy
I already do that. But subclassing and event filtering are for different purposes and non-interchangeable in my case.
erelender
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 http://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!
Yuriy Zhyromskiy
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.
erelender
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.
Yuriy Zhyromskiy
+3  A: 

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);
baysmith
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.
erelender
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.
baysmith
erelender
As requested, the first solution has been appended as an alternative solution.
baysmith
Thank you, again.
erelender