Assume following structure:
MainWindow
--->MySpecialWidget
|-->QLineEdit
|-->QSpinBox
|-->QPushButton
---><Basically any other Widget accepting QMouseEvent>
Clicking on any on the above mentioned will cause its respective feature to be activated and the QMouseEvent to be accepted and discarded.
I would like to react inside my MainWindow on any mouseclick in a generic way. More specifically I would like to hinder basic Qt widgets from accepting QMouseEvent
while still reacting to it in their usual way. Not accepting should only occur when they are children of MySpecialWidget
. Since the QMouseEvent
is accepted two layers deep, my MainWindow can not access it by the means of a direct eventFilter
.
My current solution (simplified):
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);
}
I was also thinking about attaching my MainWindows
eventfilter to everything relevant but that sounds like a nightmare to handle in bigger projects.
The question arises: How can I handle and filter events that are accepted and discarded deep inside some hierarchy without having to subclass every component on the way?
Has anyone ever done something similar or do you know if it is even possible in another way? Is my current solution acceptable?
Edit: I noticed for different QWidgets
you get different behavior when a QMouseEvent
is "eaten". For example MySpecialWidget
can filter QMouseEvents
of QLineEdit
but can not of QSpinBox
since it itself contains a QLineEdit
. I find this behavior of this library highly irritating.
Edit2 clarification: Although vahanchoos comment would solve the problem, I'm looking for a solution that can work with MySpecialWidget
without touching the QApplication
or contained classes.
Any comment on my approach or the feasibility of my request would be highly appriciated!
I hope I understood the keypoint behind this question.
Basically, if your issue is "How to catch the events for a big number of widgets of various type, including those that are made of sub-widgets (like QSpinbox > QLineEdit
) without making it a nightmare to manage", you can make use of QObject::findChildren
.
More precisely, add this to your window constructor after the call to ui->setupUi()
and that will catch everything under the instance of MySpecialWidget
:
auto children = ui->mySpecialWidget->findChildren<QWidget*>(QString(), Qt::FindChildrenRecursively);
for (QWidget* w : children)
w->installEventFilter(ui->mySpecialWidget);
As you probably already understood, this will explore all its children widget (recursively) and install the instance as a common event filter for all.
Side note:
Something is wrong with your implementation of MySpecialWidget::eventFilter
. It is supposed to return a boolean. Overriding this method usually is done like this:
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);
}