问题 QGraphicsView和eventFilter


这已经困扰了我两天多,所以我想我应该问。我在Win7上使用Qt 4.5.3(用VC2008编译)。

我有MyGraphicsView(继承QGraphicsView)和MyFilter(继承QObject)类。

当我将MyFilter对象作为事件过滤器安装到MyGraphicsView时,鼠标事件被传递给MyFilter  它们被发送到MyGraphicsView,而Key事件被发送到MyFilter 之前 它们被发送到MyGraphicsView。

在第二种情况下,我将MyFilter对象作为事件过滤器安装到MyGraphicsView-> viewport()(这是一个标准的QGLWidget),鼠标事件被传递给MyFilter 之前 它们被传递到MyGraphicsView,而Key事件被传递给 只要 MyGraphicsView。

事件应该在传递给实际对象之前传递给事件过滤器,为什么会发生这种情况呢?我该怎么做才能确保这个订单?

提前致谢。 最好的祝福。


4624
2018-03-15 09:12


起源

由于ordet似乎是个问题,因此您的代码可能会有用。 - gregseth
好的家伙,这里是重现问题的最小代码的链接。 rapidshare.com/files/363574158/QGVEF.rar - erelender


答案:


QGraphicsView是QAbstractScrollArea的子类,它是这些行为的原因。

在第一种情况下,当调用setViewport()时,QAbstractScrollArea将自身添加为MyGraphicsView的事件过滤器。 QAbstractScrollArea的事件过滤器捕获鼠标事件,首先通过viewportEvent()发送它,然后传递给传播到MyGraphicsView鼠标事件处理程序的QWidget事件处理。只有在此之后,QAbstractScrollArea的事件过滤器才会完成并且MyFilter才能运行。

在第二种情况下,关键事件仅传递给MyGraphicsView,因为在setViewport()中,QAbstractScrollArea将自身设置为焦点代理。如果使用以下代码重置焦点代理,则将传递键事件。

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

12
2018-03-23 16:01



实际上,这就是我现在正在做的事情,但我认为这更像是一种解决方法,而不是解决方案。我的事件过滤器来自插件,我不认为处理基于对象的事件过滤应该是他们关注的问题。不过,感谢您解释为什么会这样。 - erelender
虽然我认为我之前的解释一般是正确的,但我认为现在这是一个更好的解释。如果您不关心滚动区域的键事件处理(向上翻页,向下翻页等),则在视口上安装事件过滤器并清除其焦点代理是一种更简单的解决方案。否则,在MyGraphicsView和视口上安装事件过滤器可能会更好。 - baysmith
你是对的,你以前的解决方案可能更适合一般用途。在我的情况下,我试图用Qt和OSG做一些奇特的东西,这就是为什么我的大多数问题都没有解决:)。这个解决方案就像手套一样适合我的情况,谢谢。但是为了将来参考,您可以将旧解决方案作为另一个答案发布,以便其他人可以看到它吗?可通过“edited:... ago”链接访问。 - erelender
根据要求,第一个解决方案已作为替代解决方案附加。 - baysmith
再次感谢你。 - erelender


如何尝试不使用过滤器,但在MyGraphicsView重新实现必要的QEvent处理程序,如下所示:

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

-2
2018-03-19 08:19



我已经这样做了。但是子类化和事件过滤是出于不同目的而在我的情况下是不可互换的。 - erelender
好的,如果你真的需要事件过滤,可能是eventFilter()方法返回的错误的true / false-value有问题,请确保不是你的情况。我还上传了测试项目 uploading.com/files/7c7adam5/graphicsview.zip 处理事件的假设。它已经在Slackware Linux上编译,当前的git版本为Qt。因此,如果这个测试项目不适用于您的Qt版本(4.5.3),那么Qt的问题已经解决了,但对我来说并不是一个例子。它也可以是平台相关的“功能”。祝你好运! - Yuriy Zhyromskiy
您的示例也适用于Qt 4.5.3,因为它与我的情况不同。在您的示例中,graphicsview子类QWidget,而不是QGraphicsView。事件过滤器也安装在graphicsview(QWidget的子类)上,而不是QGraphicsView上,我发布了重现问题的示例代码。如果你看一下,你会更好地理解我的问题。 - erelender
是的你是对的,想念那个,对不起。看过你的项目,并调查如果你移动场景创建,设置视口和两个(取消注释第二个)过滤器到MyGraphicsView的构造函数应用程序将按预期工作,尝试实现为什么现在。 - Yuriy Zhyromskiy