pythonpyqt5qgroupboxqboxlayout

Add QGroupBox to the top of an QHBoxLayout


I am making a program and need to bring this QGroupBox (See image) to the top above the other two (See other image).

Thats my code:

def __init__(self, *args, **kwargs):
    super().__init__()

    self.setWindowTitle('Wydbid - Center')
    self.setGeometry(0, 0, 1920, 1080)

    self.setLayout(QHBoxLayout())
    self.layout().setContentsMargins(30, 30, 30, 30)

    self.setupUI()

def setupUI(self):
   datetime = QGroupBox(parent=self, title='Datum und Uhrzeit')
   datetime.setFixedHeight(150)

   action_list = QGroupBox(parent=self, title='Aktionen')
   action_list.setFixedWidth(200)

   action_list.setLayout(QGridLayout())
   action_list.layout().setAlignment(Qt.AlignTop| Qt.AlignHCenter)

   customer_note = QLabel(parent=action_list, text='Kunden')
   add_customer = ActionButton.ActionButton(parent=action_list, text='Kunde hinzufügen ➜')

   action_list.layout().addWidget(customer_note, 0, 0, 1, 0, Qt.AlignLeft)
   action_list.layout().addWidget(add_customer, 1, 0, 1, 0, Qt.AlignCenter)

   customer_list_box = QGroupBox(parent=self, title='Kundenliste')

   self.layout().addWidget(datetime)
   self.layout().addWidget(action_list)
   self.layout().addWidget(customer_list_box)

Now

How it should look


Solution

  • The simplest solution would be to use a QGridLayout as main layout, then use the column span argument of addWidget() as "2" for the groupbox, meaning that the widget will occupy two horizontal cells in the layout.

    class MyWidget(QWidget):
        def __init__(self, *args, **kwargs):
            super().__init__()
    
            self.setWindowTitle('Wydbid - Center')
            self.setGeometry(0, 0, 1920, 1080)
    
            self.setupUI()
    
        def setupUI(self):
            datetime = QGroupBox(parent=self, title='Datum und Uhrzeit')
            datetime.setFixedHeight(150)
    
            action_list = QGroupBox(parent=self, title='Aktionen')
            action_list.setFixedWidth(200)
    
            actionLayout = QGridLayout(action_list)
            actionLayout
            actionLayout.setAlignment(Qt.AlignTop| Qt.AlignHCenter)
    
            customer_note = QLabel(parent=action_list, text='Kunden')
            add_customer = ActionButton.ActionButton(parent=action_list, text='Kunde hinzufügen ➜')
    
            actionLayout.addWidget(customer_note, 0, 0, 1, 0, Qt.AlignLeft)
            actionLayout.addWidget(add_customer, 1, 0, 1, 0, Qt.AlignCenter)
    
            customer_list_box = QGroupBox(parent=self, title='Kundenliste')
    
            mainLayout = QGridLayout(self)
            mainLayout.setContentsMargins(30, 30, 30, 30)
            # the "datetime" widget will occupy the first row, spanning two
            # columns of the grid
            mainLayout.addWidget(datetime, 0, 0, 1, 2)
            # the other widgets are added to the second row, placed in the
            # first and second column respectively
            mainLayout.addWidget(action_list, 1, 0)
            mainLayout.addWidget(customer_list_box, 1, 1)
    

    Note that continuously calling layout() in the same function is pointless, as it creates unnecessary boilerplate and makes code less readable; as you can see, it's much clearer (and cleaner) to keep a local reference for the layout.

    A grid layout might not always be the optimal solution, though, especially for widgets that could dynamically create/remove children, or whenever the layout is more complex and requires different row/column spans to achieve the wanted result.

    Qt layouts can be nested, meaning that you can add a "child" layout to a "parent" layout. In this way, while the hierarchy of the layout is a bit more complex, allows at the same time more clarity of the whole structure.

    In the following code, the main layout is a vertical one, and the two bottom widgets are added to a nested horizontal layout.

    class MyWidget(QWidget):
        # ...
        def setupUI(self):
            # ...
            mainLayout = QVBoxLayout(self)
            mainLayout.setContentsMargins(30, 30, 30, 30)
            mainLayout.addWidget(datetime)
    
            bottomLayout = QHBoxLayout()
            mainLayout.addLayout(bottomLayout)
    
            bottomLayout.addWidget(action_list)
            bottomLayout.addWidget(customer_list_box)