My environment is the following:
-platform win32-msvc2013 -opengl desktop -no-icu -skip webkit
Consider the following setup (A QScrollArea containing a centered widget with fixed size):
QScrollArea scrollArea;
scrollArea.setAlignment(Qt::AlignCenter);
scrollArea.setWidgetResizable(false);
QWidget scrollAreaWidgetContents;
scrollArea.setWidget(scrollAreaWidgetContents);
Now, I want to resize that widget within my program like the following:
int w = 200, h = 200;
scrollAreaWidgetContents.setGeometry(0, 0, w, h);
And here comes the strange behavior:
If w
and h
are equal to the current width and height (i.e. nothing changes), the widget jumps to the upper left corner.
If w
and h
are different from the current width and height, the widgets stays at its centered position and changes its size correctly.
I have written a little demo application that demonstrates the issue. If you click the pushButton_Stay
button, the widgets jumps to the upper left corner.
#include <QtWidgets/QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QScrollArea>
QScrollArea *scrollArea;
QWidget *scrollAreaWidgetContents;
QPushButton *pushButton_Up;
QPushButton *pushButton_Down;
QPushButton *pushButton_Stay;
QVBoxLayout *layout;
int w = 200, h = 200;
void sizeUp() {
w += 10;
h += 10;
scrollAreaWidgetContents->setGeometry(0, 0, w, h);
}
void sizeDown() {
w -= 10;
h -= 10;
scrollAreaWidgetContents->setGeometry(0, 0, w, h);
}
void sizeStay() {
scrollAreaWidgetContents->setGeometry(0, 0, w, h);
}
int main(int argv, char **args)
{
QApplication app(argv, args);
// Scroll area
scrollArea = new QScrollArea;
scrollArea->setWidgetResizable(false);
scrollArea->setAlignment(Qt::AlignCenter);
scrollAreaWidgetContents = new QWidget();
scrollAreaWidgetContents->setGeometry(QRect(0, 0, w, h));
scrollAreaWidgetContents->setAutoFillBackground(true);
QPalette Pal(scrollAreaWidgetContents->palette());
Pal.setColor(QPalette::Background, Qt::black);
scrollAreaWidgetContents->setPalette(Pal);
scrollArea->setWidget(scrollAreaWidgetContents);
// Buttons
pushButton_Up = new QPushButton(scrollAreaWidgetContents);
pushButton_Up->setGeometry(QRect(85, 50, 31, 23));
pushButton_Up->setText("+");
pushButton_Down = new QPushButton(scrollAreaWidgetContents);
pushButton_Down->setGeometry(QRect(85, 110, 31, 23));
pushButton_Down->setText("-");
pushButton_Stay = new QPushButton(scrollAreaWidgetContents);
pushButton_Stay->setGeometry(QRect(85, 80, 31, 23));
pushButton_Stay->setText("0");
QObject::connect(pushButton_Up, &QPushButton::clicked, sizeUp);
QObject::connect(pushButton_Stay, &QPushButton::clicked, sizeStay);
QObject::connect(pushButton_Down, &QPushButton::clicked, sizeDown);
// Central layout
layout = new QVBoxLayout;
layout->addWidget(scrollArea);
// Main window
QWidget window;
window.setGeometry(200, 200, 400, 400);
window.setLayout(layout);
window.show();
return app.exec();
}
Clicking the pushButton_Up
button:
Clicking the pushButton_Stay
button:
Questions:
What's going wrong here?
Is it a bug? An if and yes, can anyone confirm it?
If it's not a bug, how can I make it that the widget always stays centered?
What's going wrong here?
Is it a bug? An if and yes, can anyone confirm it?
It seems the second call of setGeometry
with the same arguments use different origin, and the coordinates (0, 0) make the widget move to top-left corner. You can use other coordinates such as setGeometry(100, 50, w, h)
to see the difference.
Here is the source code of QWidget::setGeometry
:
if (testAttribute(Qt::WA_WState_Created)) {
d->setGeometry_sys(r.x(), r.y(), r.width(), r.height(), true);
d->setDirtyOpaqueRegion();
} else {
data->crect.setTopLeft(r.topLeft());
// ^^^^^^^^^ Could be the reason why (0, 0) move to top-left
data->crect.setSize(r.size().boundedTo(maximumSize()).expandedTo(minimumSize()));
setAttribute(Qt::WA_PendingMoveEvent);
setAttribute(Qt::WA_PendingResizeEvent);
}
Personally I think it's a bug, but more evidences need to be provided until we can confirm it.
If it's not a bug, how can I make it that the widget always stays centered?
Actually you don't have to call setGeometry
if you just want to resize the widget. Use resize
instead:
void sizeStay() {
scrollAreaWidgetContents->resize(w, h);
}
It solves the problem in your case.