Search code examples
pythonpython-3.xpyqt5qwidget

Size of QWidget.rect doesn't change even when I resize the main window


I have a Main window, and I want to apply some QEvent in that window mouse events like move press... etc., My problem is after I created the app and main window I resized it, but when I call the rect() function which is from QWidget it actually gives me the default (0, 0, 100, 30), I want it to give me the size of the window.

class TestTools(unittest.TestCase):
    app = QApplication([])
    main_window = QMainWindow()
    main_window.resize(958, 584)
    scene = QGraphicsScene()
    canvas = Canvas(scene, main_window)
    print(canvas.rect()) # It Print (0, 0, 100, 30) Whereas it should be (0, 0, 958, 584)
    
    def test():
       pass # There is many functions am using but I don't think it is important to share it

And This is Canvas Class

class Canvas(QGraphicsView):
def __init__(self, scene, centralwidget):
    super().__init__(scene, centralwidget)

    self.scene = scene
    background_color = Qt.white
    self.pixmap_item: QGraphicsItem = self.scene.addPixmap(QPixmap(780, 580))
    self.pixmap_item.setTransformationMode(Qt.FastTransformation)

So Where is the problem.


Solution

  • You're making an assumption based on wrong premises.

    First of all, you're just creating a widget (the QGraphicsView) with a parent. Doing this will only make the widget a child of that parent, but without any size constraints: the widget is just "floating" inside its parent, so it will have a default size that usually is 100x30 for new child widgets (and 640x480 for widgets without parent set in the constructor)).

    If you want to adjust the child to the parent it must be added to a layout. QMainWindow has its own (private) layout manager that uses a central widget to show the "main" content of the window, so if that QGraphicsView is going to be the only widget, you can just set that using main_window.setCentralWidget(canvas).

    Then, a widget doesn't usually receive a resizeEvent until it's mapped the first time, unless it's manually resized. When it's shown the first time, any non previously layed out item receives the resize event. Since you're not showing the main window, no resize event is emitted, but even in that case, you resized the window before adding the child, so you would still see the same default size.

    In order to ensure that the layout is properly computed even without showing the widget in which it is set, activate() must be explicitly called.

    So, summing it up:

    • widgets must be added to a layout in order to adapt their size to their parent;
    • whenever a QMainWindow is used, setCentralWidget() must be used on the "main widget";
    • manual resizing should be done after adding children to the layout in order to ensure that their geometries adapt to the parent (if you do the opposite, some size policies could result in the parent resizing itself based on the children);
    • if the widget is not going to be shown, the layout must be manually activated;
    class TestTools(unittest.TestCase):
        app = QApplication([])
        main_window = QMainWindow()
        scene = QGraphicsScene()
        canvas = Canvas(scene, main_window)
        main_window.setCentralWidget(canvas)
        main_window.resize(958, 584)
        main_window.layout().activate()
        print(canvas.rect())