Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved QWidget - identify underlying wigets

    General and Desktop
    3
    6
    1451
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S
      Sam last edited by

      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

      1 Reply Last reply Reply Quote 0
      • mrjj
        mrjj Lifetime Qt Champion last edited by mrjj

        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?

        raven-worx 1 Reply Last reply Reply Quote 0
        • raven-worx
          raven-worx Moderators @mrjj last edited by

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

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          mrjj 1 Reply Last reply Reply Quote 0
          • mrjj
            mrjj Lifetime Qt Champion @raven-worx last edited by

            @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 1 Reply Last reply Reply Quote 1
            • raven-worx
              raven-worx Moderators @mrjj last edited by raven-worx

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

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              1 Reply Last reply Reply Quote 2
              • S
                Sam last edited by Sam

                @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()));
                
                1 Reply Last reply Reply Quote 2
                • First post
                  Last post