Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QWidget - identify underlying wigets

QWidget - identify underlying wigets

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 3 Posters 1.8k Views
  • 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 Offline
    S Offline
    Sam
    wrote on last edited by
    #1

    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
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      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-worxR 1 Reply Last reply
      0
      • mrjjM 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-worxR Offline
        raven-worxR Offline
        raven-worx
        Moderators
        wrote on last edited by
        #3

        @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

        mrjjM 1 Reply Last reply
        0
        • raven-worxR raven-worx

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

          mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @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-worxR 1 Reply Last reply
          1
          • mrjjM mrjj

            @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-worxR Offline
            raven-worxR Offline
            raven-worx
            Moderators
            wrote on last edited by raven-worx
            #5

            @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
            2
            • S Offline
              S Offline
              Sam
              wrote on last edited by Sam
              #6

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

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved