1
votes

I am desperately failing at the supposedly simple problem to obtain the position and geometry of a Qt window on the screen. I originally stumbled upon this problem in a Python/PyQt context, but have since tracked it to Qt itself, where the QWidget::pos() property is not updated when the user resizes the window using any of the top or left edges or corners, i.e., resizes that involve the origin at the top left corner, hence the position of the window.

The following Qt/C++ program is the minimum to reproduce the problem (name as Qt_test.cc and build with qmake -project Qt_test.cc; qmake; make):

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QDebug>

class PrintingQWidget : public QWidget {
    Q_OBJECT
    public slots:
        void print() {
            qDebug() << pos() << width() << height();
        }
};

#include "Qt_test.moc"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    PrintingQWidget window;

    QPushButton btn("Print position", &window);
    window.connect(&btn, SIGNAL(clicked()), SLOT(print()));

    window.show();

   return app.exec();
}

Click on "Print position" to obtain the coordinates of the window, then resize the window using the top or left edges, and click again. On my system (MacOSX), the window position in the QWidget::pos() property was not updated. I clearly understand from the documentation that QWidget::pos() should always yield the coordinates of the top-left corner of the widget, which is not the case.

Anyone able to reproduce this problem? Any workarounds?

2
From the link to the documentation, it states that pos is the position relative to the parent's widget, unless the widget is a QWindow, in which case, it will give the desktop coordinates. As you've not created a QWindow, but just a QWidget, it will not return the desktop position, but the position relative to its parent which is not the desktop. As a 'workaround', create a window, add the button and get the pos of the window.TheDarkKnight
Thanks for the leads. However, it appears QWindow is only available in Qt 5. In Qt 4, it appears that QWidgets without parents simply become windows. I tried QMainWindow, but it behaves in the same way since it inherits from QWidget. Also, the coordinates of pos() are clearly the desktop position. They are just not updated properly upon resize.Stefan
Try widget->mapToGlobal( widget->pos() )TheDarkKnight
I tried mapToGlobal, which does get updated upon resize. However, I can't make sense out of the coordinates it returns. They are clearly not screen coordinates. It is strange that it returns anything at all, since my QWidget does not have a parent.Stefan
What sort of coordinates are you getting? Alternatively, have you tried getting the widget geometry?TheDarkKnight

2 Answers

2
votes

OK, it appears that this is actually a bug in Qt 4.8. My example program, as well as Merlin069's version, behave perfectly fine with Qt 5. Both Qt 4.8.2 and Qt 4.8.4 are affected by the bug. (For Qt 4.8.4, I tested both the homebrew and dmg installations, which both behave incorrectly). My test system was MacOSX 10.7.5.

Maybe some of you with different systems/Qt versions can still run the test program and report back, so that I can file a better bug report?

1
votes

Looking closer at your code, you should not be including the moc file. Anyhow, I decided to code this myself and I get the correct, expected coordinates in screen space. Here's the code: -

Header (widget.h)

#include <QWidget>
#include <QDebug>
class MyWidget : public QWidget
{
    Q_OBJECT
public:
    MyWidget(QWidget* parent = NULL)
        : QWidget(parent)
    {
    }

    virtual ~MyWidget()
    {
    }

public slots:
    void PrintPos() const
    {
        qDebug() << pos() << width() << height();
    }
};

Main.cpp

#include "widget.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyWidget debugWidget(NULL);

    QPushButton btn("print position", &debugWidget);
    QObject::connect(&btn, &QPushButton::released, &debugWidget, &MyWidget::PrintPos);

    debugWidget.show();

   return app.exec();
}