Search code examples
pythonpython-3.xpyqtpyqt5qlayout

Issues with sizing when I add widget to Vbox Layout


I'm running to issues with QLayouts.

class welcomeWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.initText()
        self.organize()

    def initText(self):
        self.welcome = QLabel("Welcome to Name!", self)
        self.info = QLabel("This program allows you to....", self)
        self.message = QLabel("First, you must enter some data...", self)
        self.proceed = QLabel("Click on 'Next >>' to proceed.", self)

    def organize(self):
        vbox = QVBoxLayout(self)
        scroll = QScrollArea(self)
        vbox.addWidget(scroll)
        wid = QWidget(self)
        vevobox = QVBoxLayout(wid)

        vv = QVBoxLayout()
        vv.addWidget(self.welcome)
        vv.addWidget(self.info)
        vevobox.addLayout(vv)
        self.show()

It looks like this... image

Idk what to do, and whenever I add the other QLabels they all just disappear.


Solution

  • Before showing the solution you have to explain some things:

    • There are 3 ways to set a layout in a widget:

      1. Create the widget without a parent and then the widget indicates that it uses that layout with setLayout():

        lay = QVBoxLayout()
        foo_widget.setLayout(lay)
        
      2. Point to what widget to manage when the layout is built.

        lay = QVBoxLayout(foo_widget)
        
      3. The previous methods are equivalent, but the third method is to establish it as the son of an already established layout.

    • A widget can only have a layout as a top-level, so if only the last one remains:

      lay1 = QVBoxLayout(foo_widget)
      lay2 = QVBoxLayout(foo_widget)
      
      # The above is equivalent to:
      
      lay1 = QVBoxLayout()
      lay2 = QVBoxLayout(foo_widget)
      
    • A widget is the son of another widget when it is set as a parent in the constructor, or it is established as part of a layout that handles the position of the widget:

      1.

      child_1 = Foo_Widget(some_widget)
      

      2.

      lay = Foo_Layout(some_widget)
      child_2 = Foo_Widget()
      lay.addWidget(child_2)
      

    So if you consider the above you can reduce your code:

    ...
    def initText(self):
        self.welcome = QLabel("Welcome to Name!")
        self.info = QLabel("This program allows you to....")
        self.message = QLabel("First, you must enter some data...", self)
        self.proceed = QLabel("Click on 'Next >>' to proceed.", self)
    
    def organize(self):
        vbox = QVBoxLayout(self)
        scroll = QScrollArea()
        vbox.addWidget(scroll)
    
        wid = QWidget(self)
        vevobox = QVBoxLayout(wid)
    
        vv = QVBoxLayout()
        vv.addWidget(self.welcome)
        vv.addWidget(self.info)
        vevobox.addLayout(vv)
    
        self.show()
    

    Using the above, the following tree can be assembled:

    welcomeWidget
    ├── message
    ├── proceed
    ├── vbox (QVBoxLayout)
    │   └── scroll
    └── wid 
        └── vevobox (QVBoxLayout)
            └──vv (QVBoxLayout)
               ├── info
               └── welcome
    

    And as you see is what is expected, for example there are 2 labels that are shown behind everything since they were first established without a layout, then a layout was established where the QScrollArea was placed, so this last one took all the available space , and finally the wid widget without layout was placed so it will be in the top-left position, and within that widget the remaining 2 labels were established.

    The idea is to have the following structure:

    welcomeWidget
    └── vbox (QVBoxLayout)
        └── scroll
            └── wid
                └── vv (QVBoxLayout)
                    ├── info
                    ├── message
                    ├── proceed
                    └── welcome
    

    Using the above you get the following:

    class welcomeWidget(QWidget):
        def __init__(self):
            super().__init__()
            self.initText()
            self.organize()
    
        def initText(self):
            self.welcome = QLabel("Welcome to Name!")
            self.info = QLabel("This program allows you to....")
            self.message = QLabel("First, you must enter some data...")
            self.proceed = QLabel("Click on 'Next >>' to proceed.")
    
        def organize(self):
            vbox = QVBoxLayout(self)
            scroll = QScrollArea()
            scroll.setWidgetResizable(True)
    
            wid = QWidget()
            scroll.setWidget(wid)
    
            vv = QVBoxLayout(wid)
            vv.addWidget(self.welcome)
            vv.addWidget(self.info)
            vv.addWidget(self.message)
            vv.addWidget(self.proceed)
            vv.addStretch()
    
            vbox.addWidget(scroll)
            self.show()