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.

    alt text

    I already tried widgetAt, topLevelAt and childAt but it doesn't full fill my requirement.

    TIA
    Sam


  • Qt Champions 2016

    Hi
    Not sure why widgetAt did not work for you `?
    http://doc.qt.io/qt-5/qapplication.html#widgetAt

    Did you convert from event->pos that is in local coordinates to global coordinates
    when using widgetAt?


  • Moderators

    @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.


  • Qt Champions 2016

    @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}
    

  • Moderators

    @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.



  • @mrjj @raven-worx

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

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.