QGraphicsView и eventFilter

Это прослушивало меня уже более двух дней, поэтому я подумал, что должен спросить. Я использую Qt 4.5.3 (скомпилированный с VC2008) на Win7.

У меня есть MyGraphicsView (наследует QGraphicsView) и MyFilter (наследует классы QObject).

Когда я устанавливаю объект MyFilter в качестве фильтра событий в MyGraphicsView, события Mouse доставляются в MyFilter после их доставки в MyGraphicsView, тогда как события Key доставляются в MyFilter до их доставки в MyGraphicsView.

Во втором случае я устанавливаю объект MyFilter как фильтр событий в MyGraphicsView- > viewport() (который является стандартным QGLWidget), события Mouse доставляются в MyFilter до того, как они будут доставлены в MyGraphicsView, тогда как ключевые события будут доставлены только для MyGraphicsView.

Предполагается, что события должны доставляться фильтрам событий до их доставки на фактический объект, так почему это происходит? Что я должен сделать, чтобы обеспечить этот порядок?

Спасибо заранее. С наилучшими пожеланиями.

Ответ 1

QGraphicsView является подклассом QAbstractScrollArea, который является причиной такого поведения.

В первом случае QAbstractScrollArea добавляет себя как фильтр событий в MyGraphicsView, когда вызывается setViewport(). Фильтр событий QAbstractScrollArea захватывает событие мыши, сначала отправляет его через viewportEvent(), а затем в обработку событий QWidget, которая распространяется на обработчики событий мыши MyGraphicsView. Только после этого завершается фильтрация событий QAbstractScrollArea и запускается MyFilter.

Во втором случае ключевые события доставляются только в MyGraphicsView, потому что в setViewport() QAbstractScrollArea устанавливает себя как фокус-прокси. Если прокси-сервер фокуса reset со следующим кодом, будут переданы ключевые события.

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

Альтернативой является установка фильтра событий как на графическом представлении, так и на его видовом экране, но модифицируйте фильтр, чтобы обрабатывать ключевые события только из одного объекта и событий мыши из другого.

Измените MyFilter.h

  QObject *keyObj;
  QObject *mouseObj;

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

Измените MyFilter.cpp

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

и

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

Измените 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);

Ответ 2

Как пробовать не использовать фильтр, а переопределять необходимые обработчики QEvent в MyGraphicsView, как здесь:

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