QWidget - identify underlying wigets
-
Hi,
I have a frame with a number of widgets, on top of that frame lies a translucent Overlay widget (activated based on a property). I would like to know if there is way I can identify the underlying widgets under this Overlay widget on mousePress ( based on event->pos())
The fame itself can have multiple layers e.g with stackLayout and I would like to know the top level widgets from there.
I already tried widgetAt, topLevelAt and childAt but it doesn't full fill my requirement.
TIA
Sam -
Hi
Not sure why widgetAt did not work for you `?
http://doc.qt.io/qt-5/qapplication.html#widgetAtDid you convert from event->pos that is in local coordinates to global coordinates
when using widgetAt? -
Hi
Not sure why widgetAt did not work for you `?
http://doc.qt.io/qt-5/qapplication.html#widgetAtDid you convert from event->pos that is in local coordinates to global coordinates
when using widgetAt?@mrjj said in QWidget - identify underlying wigets:
Not sure why widgetAt did not work for you `?
because the overlay widget is returned in all times ;)
@Sam
eitherway you quickly hide the overlay for the childAt() call.
If there is noticeable flickering, you need to implement a custom recursive method to do what you want. It is pretty simple. Take a look at the source code of QWidget::childAt() and add a line to skip the child if it is your overlay. -
@mrjj said in QWidget - identify underlying wigets:
Not sure why widgetAt did not work for you `?
because the overlay widget is returned in all times ;)
@Sam
eitherway you quickly hide the overlay for the childAt() call.
If there is noticeable flickering, you need to implement a custom recursive method to do what you want. It is pretty simple. Take a look at the source code of QWidget::childAt() and add a line to skip the child if it is your overlay.@raven-worx
Eh doh yes.. :)
My brain wanted the call to be like parentwidget->WidgetAt() as to skip Overlay. Missed it was QApp ;)If we look at the function, it seems it can go through
WA_TransparentForMouseEvents ?
So if Overlay is marked with WA_TransparentForMouseEvents it should return the
widget beneath ? Or is "shoot a hole in the widget" not what i think :)QWidget *QApplication::widgetAt(const QPoint &p) 1236{ 1237 QWidget *window = QApplication::topLevelAt(p); 1238 if (!window) 1239 return 0; 1240 1241 QWidget *child = 0; 1242 1243 if (!window->testAttribute(Qt::WA_TransparentForMouseEvents)) 1244 child = window->childAt(window->mapFromGlobal(p)); 1245 1246 if (child) 1247 return child; 1248 1249 if (window->testAttribute(Qt::WA_TransparentForMouseEvents)) { 1250 //shoot a hole in the widget and try once again, 1251 //suboptimal on Qt for Embedded Linux where we do 1252 //know the stacking order of the toplevels. 1253 int x = p.x(); 1254 int y = p.y(); 1255 QRegion oldmask = window->mask(); 1256 QPoint wpoint = window->mapFromGlobal(QPoint(x, y)); 1257 QRegion newmask = (oldmask.isEmpty() ? QRegion(window->rect()) : oldmask) 1258 - QRegion(wpoint.x(), wpoint.y(), 1, 1); 1259 window->setMask(newmask); 1260 QWidget *recurse = 0; 1261 if (QApplication::topLevelAt(p) != window) // verify recursion will terminate 1262 recurse = widgetAt(x, y); 1263 if (oldmask.isEmpty()) 1264 window->clearMask(); 1265 else 1266 window->setMask(oldmask); 1267 return recurse; 1268 } 1269 return window; 1270}
-
@raven-worx
Eh doh yes.. :)
My brain wanted the call to be like parentwidget->WidgetAt() as to skip Overlay. Missed it was QApp ;)If we look at the function, it seems it can go through
WA_TransparentForMouseEvents ?
So if Overlay is marked with WA_TransparentForMouseEvents it should return the
widget beneath ? Or is "shoot a hole in the widget" not what i think :)QWidget *QApplication::widgetAt(const QPoint &p) 1236{ 1237 QWidget *window = QApplication::topLevelAt(p); 1238 if (!window) 1239 return 0; 1240 1241 QWidget *child = 0; 1242 1243 if (!window->testAttribute(Qt::WA_TransparentForMouseEvents)) 1244 child = window->childAt(window->mapFromGlobal(p)); 1245 1246 if (child) 1247 return child; 1248 1249 if (window->testAttribute(Qt::WA_TransparentForMouseEvents)) { 1250 //shoot a hole in the widget and try once again, 1251 //suboptimal on Qt for Embedded Linux where we do 1252 //know the stacking order of the toplevels. 1253 int x = p.x(); 1254 int y = p.y(); 1255 QRegion oldmask = window->mask(); 1256 QPoint wpoint = window->mapFromGlobal(QPoint(x, y)); 1257 QRegion newmask = (oldmask.isEmpty() ? QRegion(window->rect()) : oldmask) 1258 - QRegion(wpoint.x(), wpoint.y(), 1, 1); 1259 window->setMask(newmask); 1260 QWidget *recurse = 0; 1261 if (QApplication::topLevelAt(p) != window) // verify recursion will terminate 1262 recurse = widgetAt(x, y); 1263 if (oldmask.isEmpty()) 1264 window->clearMask(); 1265 else 1266 window->setMask(oldmask); 1267 return recurse; 1268 } 1269 return window; 1270}
@mrjj
yes, but then you won't receive the mouseevent on the overlay again to trigger all this.Edit:
but actually i think it can be made work with
Qt::WA_TransparentForMouseEvents
:void OverlayWidget::mousePressEvent(QMouseEvent* event) { this->setAttribute( Qt::WA_TransparentForMouseEvents, true ); QWidget* childBeneath = this->childAt( event->pos() ); this->setAttribute( Qt::WA_TransparentForMouseEvents, false ); }
This should work.
-
void OverlayWidget::mousePressEvent(QMouseEvent* event)
{
this->setAttribute( Qt::WA_TransparentForMouseEvents, true );
QWidget* childBeneath = this->childAt( event->pos() );
this->setAttribute( Qt::WA_TransparentForMouseEvents, false );
}Thanks a lot guys this works perfect :-) I just changed from childAt() to widgetAt()
qApp->widgetAt(mapToGlobal(e->pos()));