I have PyQt5 QLabels that expand/contract as the QMainWindow size changes. I want to get the dimensions of the QLabels when the QMainWindow is sized to anything other that its initial dimensions.
The script below creates two QLabels in a QMainWindow. The QLabels expand but the top QLabel has a fixed height. The QMainWindow is created with dimensions 400x300 and and displays as screen maximized using showMaximized()
(in my case, 1920 x 1080). The script prints the dimensions of the QLabels before and after the QMainWindow displays. Prior to display, width()
and height()
return default QLabel values and after display (screen maximized) width()
and height()
return values as if the QMainWindow has physical dimensions of 400x300. Here is wat is printed:
label_1 Size Before Expanding: 100 100
label_2 Size Before Expanding: 100 30
label_1 Size After Expanding: 378 100
label_2 Size After Expanding: 378 171
How can I get the true dimensions for the QLabels when the QMainWindow is maximized? I'm running in a Windows environment.
from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QLabel, QVBoxLayout, QWidget
import sys
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
central_widget = QWidget()
self.setCentralWidget(central_widget)
self.setGeometry(100, 100, 400, 300)
self.layout = QVBoxLayout(central_widget)
self.label_1 = QLabel(self)
self.label_1.setStyleSheet('background-color: green')
self.label_1.setFixedHeight(100)
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.label_1.setSizePolicy(sizePolicy)
self.layout.addWidget(self.label_1)
self.label_2 = QLabel(self)
self.label_2.setStyleSheet('background-color: red')
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.label_2.setSizePolicy(sizePolicy)
self.layout.addWidget(self.label_2)
print('label_1 Size Before Expanding: ', self.label_1.width(), self.label_1.height())
print('label_2 Size Before Expanding: ', self.label_2.width(), self.label_2.height())
self.showMaximized()
print('label_1 Size After Expanding: ', self.label_1.width(), self.label_1.height())
print('label_2 Size After Expanding: ', self.label_2.width(), self.label_2.height())
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
app.exec()
When widgets are created but not yet mapped ("shown") on the screen, they always have a default size:
setParent()
);The only exception is when size constraints exist, like in your case: the first label has a fixed height, and that's what is shown in the output (remember that "fixed size" means that both minimum and maximum sizes are the same).
Calling
show()
orsetVisible(True)
the first time, automatically creates (amongst others) aResize
event on the top level or parent widget, which automatically activates the layout for that widget and eventually recursively createsResize
events for all widgets managed by its layout, based on the layout computations. This does not happen before showing the widgets the first time.This is done for optimization reasons: updating a layout can be very demanding, especially for complex UIs with multiple nested layouts that contain widgets that have different size hints, policies, stretches, etc.
Since geometries will be updated anyway as soon as the window will be shown, there's no point in setting a size until the full layout has been completed. Also note that using
setGeometry()
orresize()
prior showing the widget the first time will not activate the layout, as explained above.That said, it is possible to update sizes based on the current layout even if widgets have not been shown yet: you have to explicitly
activate()
the layout manager. This is also normally achieved by calling the layout'ssizeHint()
, after it has been set on its widget.But, be aware: in order to get the correct sizes based on the layout, you need to activate all layouts, up to the top level widget. QMainWindow has its own private layout, so you need to activate that too.
Since you've overwritten the default
layout()
function withself.layout
, the only way to access it is through thesuper()
call.Then, there's another problem: functions that change the window state (maximized, minimized, full screen and normal) do not directly resize the window. Those functions (including
setWindowState()
) actually "ask" the OS to change the window state, then the OS will decide on its own if the request is acceptable and eventually resize the window according to its behavior based on the requested state.That resizing will happen at an undefined point after that call, and there's no direct way to know when: the OS might have some fancy animation to show the state change, and that might cause continuous changes in the size or even an abrupt change to the new size after that "process" has finished. Even using
processEvents()
won't be enough, since that function only processes events directly handled by Qt, and Qt cannot know anything about external OS events.The only way to know for sure the size of widgets after any resizing, is by overriding the
resizeEvent()
.This will correctly print, before
showMaximized()
:Note that the
resizeEvent
is called twice: the first one is right after anyshow*()
call, the second is when the window has been actually maximized. If you remove theactivate
calls above, the first output will be the same as the default values explained at the beginning.