我如何处理和过滤在某些层次结构深处被接受和丢弃的事件,而不必在途中子类化每个组件?



假设结构如下:

MainWindow
--->MySpecialWidget
|-->QLineEdit
|-->QSpinBox
|-->QPushButton
---><Basically any other Widget accepting QMouseEvent>

点击上面提到的任何一个将导致其各自的特性被激活,QMouseEvent被接受和丢弃。

我想在我的主窗口内以通用的方式对任何鼠标点击作出反应。更具体地说,我想阻止基本的Qt小部件接受QMouseEvent,同时仍然以他们通常的方式对它做出反应。不接受应该只发生在他们是MySpecialWidget的孩子的时候。由于QMouseEvent被接受为两层深,我的主窗口不能通过直接的eventFilter访问它。

我当前的解决方案(简化):

void MySpecialWidget::eventFilter(QObject *o, QEvent *e)
{
if(e->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mE = static_cast<QMouseEvent*>(e);

QMouseEvent newMouseEvent = new QMouseEvent(QMouseEvent::MouseButtonPress, mE->pos(), mE->button(), mE->buttons(), mE->modifiers());
qApp->notify(this, &newMouseEvent);
// Check how this handled the copied Mouseevent
return /*result of check*/;
}
return Base::eventFilter(o, e);
}

我还在考虑将我的MainWindows事件过滤器附加到所有相关的内容,但这听起来像是在更大的项目中处理的噩梦。

问题出现了:我如何处理和过滤在某个层次结构深处被接受和丢弃的事件,而不必在此过程中对每个组件进行子类化?

有没有人做过类似的事情,或者你知道是否有可能以另一种方式实现?我当前的解决方案可以接受吗?

编辑:我注意到对于不同的QWidgets,当QMouseEvent被"吃掉"时,你会得到不同的行为。例如,MySpecialWidget可以过滤QLineEditQMouseEvents,但不能过滤QSpinBox,因为它本身包含QLineEdit。我发现这个库的这种行为非常令人恼火。

Edit2澄清:虽然vahanchos的评论将解决问题,我正在寻找一个解决方案,可以与MySpecialWidget工作,而不触及QApplication或包含的类。

对我的方法或我的请求的可行性的任何评论将是非常感谢的!

我希望我理解了这个问题背后的关键。

基本上,如果你的问题是"如何捕获各种类型的大量小部件的事件,包括那些由子小部件(如QSpinbox > QLineEdit)组成的事件,而不使其成为管理的噩梦",你可以使用QObject::findChildren

更准确地说,在调用ui->setupUi()之后将它添加到您的窗口构造函数中,它将捕获MySpecialWidget实例下的所有内容:

auto children = ui->mySpecialWidget->findChildren<QWidget*>(QString(), Qt::FindChildrenRecursively);
for (QWidget* w : children)
w->installEventFilter(ui->mySpecialWidget);

您可能已经理解,这将探索它的所有子部件(递归地),并将实例安装为所有子部件的公共事件过滤器。


注:

MySpecialWidget::eventFilter的实现有问题。它应该返回一个布尔值。重写这个方法通常是这样做的:

bool MySpecialWidget::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
//do something
return true;
}
else // standard event processing
return QObject::eventFilter(obj, event);
}

我记得做过类似的事情来简化大量切换鼠标事件。它基本上是由一个"看不见的盾牌"组成的。控件悬停在我想要阻止的控件上。当可见时,这个视图捕捉到所有事件;不然,他们就往前走,"经过"了。它。

你可以使用QStackedLayout来实现它,把盾放在堆栈的顶部,并将堆叠模式设置为StackAll。当捕获事件时,您可以处理它们,然后不接受事件,让它通过。

这里的主要缺点是它会改变你的MySpecialWidget是如何设计的,由于堆叠布局,但这将取决于你的UI架构。

最新更新