Determine mouse press on dialog or child widget?
-
I have a draggable dialog with bunch of labels on it. I only want to detect mouse events (down, move, release) on dialog (not on child widgets/labels). QLabel doesn't capture any mouse events resulting in parent/main window receiving those events.
Is there a way to manually Hit-test dialog or have Qlabel widgets accept mouse events so that dialog doesn't receive those?
-
@Taytoo
There are several ways to accomplish this. Most involve either subclassing your child widgets or installing an event filter on each one. I'm thinking these would cause you hassle/a lot of work.One way I would propose which does not involve these is:
/*virtual*/ void Dialog::mousePressEvent(QMouseEvent *mouseEvent) /*override*/ { QWidget *w = QApplication::widgetAt(mouseEvent->globalPos()); if (w != nullptr && w != this) qDebug() << "Dialog::mousePressEvent on some other widget" << w << w->objectName(); else qDebug() << "Dialog::mousePressEvent on Dialog"; }
[Note thiis is Qt5. For Qt6 they may have changed to
mouseEvent->globalPosition()
?]You can also define an event filter just on the dialog to stop propagation of events on sub-widgets to the dialog, along the lines of:
// this->installEventFilter(this); bool Dialog::eventFilter(QObject *object, QEvent *event) { QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event); if (mouseEvent) { QWidget *w = QApplication::widgetAt(mouseEvent->globalPos()); if (w != nullptr && w != this) { qDebug() << "Dialog::eventFilter on some other widget" << w << w->objectName(); return true; } else qDebug() << "Dialog::eventFilter on Dialog"; } return false; }
You can use this to see whether a mouse event arriving at the
QDialog
level was actually over some widget inside it. It usesQApplication::widgetAt()
which is "slow", but may be fine unless you have very many widgets.I don't know whether someone else can propose a neater way?
-
@Taytoo
There are several ways to accomplish this. Most involve either subclassing your child widgets or installing an event filter on each one. I'm thinking these would cause you hassle/a lot of work.One way I would propose which does not involve these is:
/*virtual*/ void Dialog::mousePressEvent(QMouseEvent *mouseEvent) /*override*/ { QWidget *w = QApplication::widgetAt(mouseEvent->globalPos()); if (w != nullptr && w != this) qDebug() << "Dialog::mousePressEvent on some other widget" << w << w->objectName(); else qDebug() << "Dialog::mousePressEvent on Dialog"; }
[Note thiis is Qt5. For Qt6 they may have changed to
mouseEvent->globalPosition()
?]You can also define an event filter just on the dialog to stop propagation of events on sub-widgets to the dialog, along the lines of:
// this->installEventFilter(this); bool Dialog::eventFilter(QObject *object, QEvent *event) { QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event); if (mouseEvent) { QWidget *w = QApplication::widgetAt(mouseEvent->globalPos()); if (w != nullptr && w != this) { qDebug() << "Dialog::eventFilter on some other widget" << w << w->objectName(); return true; } else qDebug() << "Dialog::eventFilter on Dialog"; } return false; }
You can use this to see whether a mouse event arriving at the
QDialog
level was actually over some widget inside it. It usesQApplication::widgetAt()
which is "slow", but may be fine unless you have very many widgets.I don't know whether someone else can propose a neater way?
-
@mpergand
Doesn't do descendent grandchildren etc. ? So by the time you do it recursively what advantages does it offer? And this is only a replacement for theQApplication::widgetAt()
, hoping to make it faster, but you would follow one of the approaches above? -
-
@mpergand
Doesn't do descendent grandchildren etc. ? So by the time you do it recursively what advantages does it offer? And this is only a replacement for theQApplication::widgetAt()
, hoping to make it faster, but you would follow one of the approaches above?@JonB I tried the eventfilter approach. The problem with it is that it layouts and spacers receive input events as well, and its quite a lot of controls that I have to filter through. Is it possible to disable mouse input being sent to all layouts and spacers?