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::mapToGlobal() not giving right result
Forum Updated to NodeBB v4.3 + New Features

QWidget::mapToGlobal() not giving right result

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 3 Posters 9.2k Views 2 Watching
  • 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.
  • JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #1

    Summary: In a nutshell, is QWidget::mapToGlobal() supposed to give correct result if the widget is on a [box] layout?

    I am using maptoGlobal() to display a popup window off a QPushButton. I want the popup window to appear right where the button is. So I am using just what you would expect:

    QWidget _popup;    // no parent
    _popup.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
    
    // this is QPushButton, with parentage, on layout
    connect(this, &QPushButton::clicked, this, &UIUtils::PushButtonWithPopup::doPopup);
    
    /*slot*/ void UIUtils::PushButtonWithPopup::doPopup()
    {
        QPoint pos = this->mapToGlobal(this->pos());
        _popup.show();
        _popup.move(pos.x(), pos.y());
    }
    

    What I am finding is: when the button is at the lefthand side of window --- i.e. pos.x() ==~ 0 --- the global position is good. But as it moves right --- pos.x() > 100 etc. --- mapToGlobal(pos()) is returning an x() which is getting larger & larger, so the popup appears further & further to the right of the button. The y() however remains correct.

    Now, the button is on a QHBoxlayout. I started to read an old post
    https://www.qtcentre.org/threads/40574-mapToGlobal-mapFromGlobal-isn-t-working-properly
    which said at one point

    So it is managed by a layout which might explain why your own geometry management fails. If you wish to do your own moving/resizing, you can't use layouts at the same time.

    Is that what is going on?

    Please don't ask me to repro a full example for now, it will take too long. I would just like to quickly know: if I place a widget on a layout, does that mean I won't be able to use mapToGlobal(pos()) to get the correct global screen coordinate to position a popup at? If so, how can I map from a widget on a layout to its correct screen position? Thanks.

    J.HilkJ 1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #3

      @JonB said in QWidget::mapToGlobal() not giving right result:

      QPoint pos = this->mapToGlobal(this->pos());

      That's wrong. pos() is a position in the parent, and this->mapToGlobal maps it relatively to this, not the parent, so simply said - you're mixing different coordinate systems - local and parent. Additionally, in case of a top level widget that has no parent, pos() is already a global position.

      If you want the global position of the button you either map its position in parent relative to that parent:

      QPoint global_pos = btn->parentWidget()->mapToGlobal(btn->pos());
      

      or, simpler, and IMO more appropriate here, just map the upper left corner of your button relative to it:

      QPoint global_pos = btn->mapToGlobal(QPoint(0,0));
      
      J.HilkJ 1 Reply Last reply
      5
      • JonBJ JonB

        Summary: In a nutshell, is QWidget::mapToGlobal() supposed to give correct result if the widget is on a [box] layout?

        I am using maptoGlobal() to display a popup window off a QPushButton. I want the popup window to appear right where the button is. So I am using just what you would expect:

        QWidget _popup;    // no parent
        _popup.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
        
        // this is QPushButton, with parentage, on layout
        connect(this, &QPushButton::clicked, this, &UIUtils::PushButtonWithPopup::doPopup);
        
        /*slot*/ void UIUtils::PushButtonWithPopup::doPopup()
        {
            QPoint pos = this->mapToGlobal(this->pos());
            _popup.show();
            _popup.move(pos.x(), pos.y());
        }
        

        What I am finding is: when the button is at the lefthand side of window --- i.e. pos.x() ==~ 0 --- the global position is good. But as it moves right --- pos.x() > 100 etc. --- mapToGlobal(pos()) is returning an x() which is getting larger & larger, so the popup appears further & further to the right of the button. The y() however remains correct.

        Now, the button is on a QHBoxlayout. I started to read an old post
        https://www.qtcentre.org/threads/40574-mapToGlobal-mapFromGlobal-isn-t-working-properly
        which said at one point

        So it is managed by a layout which might explain why your own geometry management fails. If you wish to do your own moving/resizing, you can't use layouts at the same time.

        Is that what is going on?

        Please don't ask me to repro a full example for now, it will take too long. I would just like to quickly know: if I place a widget on a layout, does that mean I won't be able to use mapToGlobal(pos()) to get the correct global screen coordinate to position a popup at? If so, how can I map from a widget on a layout to its correct screen position? Thanks.

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #2

        @JonB I can reproduce it:

        int main(int argc, char *argv[])
        {
            QApplication app(argc, argv);
        
            QWidget w;
            QLabel l;
            l.setStyleSheet("background-color:red;");
            w.resize(200,50);
            QHBoxLayout *hLay = new QHBoxLayout(&w);
        
            for(int i(0); i <9; i++) {
                QPushButton *btn = new QPushButton(QString("Btn%1").arg(i));
                QObject::connect(btn, &QPushButton::clicked, &l, [=, &l]()->void{
                    QPoint p = btn->mapToGlobal(btn->pos());
                    l.resize(btn->size());
                    l.move(p);
                });
                hLay->addWidget(btn);
            }
        
            w.show();
            l.show();
        
            return app.exec();
        }
        

        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        1
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #3

          @JonB said in QWidget::mapToGlobal() not giving right result:

          QPoint pos = this->mapToGlobal(this->pos());

          That's wrong. pos() is a position in the parent, and this->mapToGlobal maps it relatively to this, not the parent, so simply said - you're mixing different coordinate systems - local and parent. Additionally, in case of a top level widget that has no parent, pos() is already a global position.

          If you want the global position of the button you either map its position in parent relative to that parent:

          QPoint global_pos = btn->parentWidget()->mapToGlobal(btn->pos());
          

          or, simpler, and IMO more appropriate here, just map the upper left corner of your button relative to it:

          QPoint global_pos = btn->mapToGlobal(QPoint(0,0));
          
          J.HilkJ 1 Reply Last reply
          5
          • Chris KawaC Chris Kawa

            @JonB said in QWidget::mapToGlobal() not giving right result:

            QPoint pos = this->mapToGlobal(this->pos());

            That's wrong. pos() is a position in the parent, and this->mapToGlobal maps it relatively to this, not the parent, so simply said - you're mixing different coordinate systems - local and parent. Additionally, in case of a top level widget that has no parent, pos() is already a global position.

            If you want the global position of the button you either map its position in parent relative to that parent:

            QPoint global_pos = btn->parentWidget()->mapToGlobal(btn->pos());
            

            or, simpler, and IMO more appropriate here, just map the upper left corner of your button relative to it:

            QPoint global_pos = btn->mapToGlobal(QPoint(0,0));
            
            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #4

            @Chris-Kawa +1 that explains so much of my past experience 🤦‍♂️

            with that in mind, this works now as well:

            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
            
                QWidget w;
                QLabel l;
                l.setStyleSheet("background-color:red;");
                w.resize(500,50);
                QHBoxLayout *hLay = new QHBoxLayout(&w);
            
                for(int i(0); i <9; i++) {
                    QPushButton *btn = new QPushButton(&w);
                    btn->setText(QString("Btn%1").arg(i));
                    QObject::connect(btn, &QPushButton::clicked, &l, [=, &l, &w]()->void{
                        QPoint p = w.mapToGlobal(btn->pos());
                        l.resize(btn->size());
                        l.move(p);
                    });
                    hLay->addWidget(btn);
                }
            
                w.show();
                l.show();
            
                return app.exec();
            }
            

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply
            2
            • JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #5

              Thank you both for prompt responses!

              @Chris-Kawa

              Additionally, in case of a top level widget that has no parent, pos() is already a global position.

              I'm a little lost here. I am trying to get the button's coordinates, the button does have parentage. It is the popup which will not have parentage, and so need global coordinates...?

              Meanwhile, I am about to try out your solutions and will report back....

              UPDATE
              Still not sure what you meant by

              QPoint global_pos = btn->mapToGlobal(QPoint(0,0));
              

              That's what I had originally (this == btn); I think you meant that if it had no parent? [EDIT No, see below]

              Anyway, altered to

              QPoint pos = this->parentWidget()->mapToGlobal(this->pos());
              

              and lo & behold the global position is correct, whether the button is at left or right of its parent/layout.

              You are an genius, thank you! :)

              EDIT
              OIC, btn->mapToGlobal(QPoint(0,0)), that's QPoint(0, 0) not btn->pos(). Got it! So now I have:

              QPoint pos = this->mapToGlobal(QPoint(0, 0));
              

              I understand what's going on!!

              1 Reply Last reply
              1

              • Login

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