简体   繁体   中英

Qt - Don't stretch widgets in QVBoxLayout

Issue

When I drag to resize window in Qt, it is stretching the widgets inside my QVBoxLayout. I would like to avoid this.

Here are a few pictures of the demo app (created for this stackoverflow post):

Screenshot: More Widgets than Space (works as expected -> scoll down to view content)

比空间更多的小部件

Screenshots: Less Widgets than Space (problem - Qt is stretching my AccountWidget items)

小部件比空间少

How can I use Qt Layouts, or other Qt Widget classes to solve this problem? Here is the code for my Demo app (about 50 lines):

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, \
    QGroupBox, QGridLayout, QLabel, QScrollArea
from typing import List

class AccountWidget(QWidget):
    def __init__(self, data: dict, parent=None):
        super().__init__(parent)        
        self.group_box_layout = QGridLayout()
        for i, (key, value) in enumerate(data.items()):
            self.group_box_layout.addWidget(QLabel(key), i+1, 1)
            self.group_box_layout.addWidget(QLabel(value), i+1, 2)
        self.group_box = QGroupBox()
        self.group_box.setLayout(self.group_box_layout)
        self.main_layout = QVBoxLayout()
        self.main_layout.addWidget(self.group_box)
        self.setLayout(self.main_layout)

class AccountListWidget(QWidget):
    def __init__(self, data: List[dict], parent=None):
        super().__init__(parent)
        self.main_layout = QVBoxLayout()
        for account_data in data:
            self.main_layout.addWidget(AccountWidget(account_data))
        self.setLayout(self.main_layout)

class MainWidget(QWidget):
    def __init__(self, data: List[dict], parent=None):
        super().__init__(parent)
        self.account_list_widget = AccountListWidget(data)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setWidget(self.account_list_widget)
        self.main_layout = QVBoxLayout()
        self.main_layout.addWidget(self.scroll_area)
        self.setLayout(self.main_layout)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    data = [{"created":"2019","balance":"100","deposits":"50","type":"Chq"},
            {"created":"2020","balance":"80","deposits":"45","type":"Chq"},
            {"created":"2020","balance":"70","deposits":"55","type":"Sav"}]
    mainWidget = MainWidget(data)
    mainWindow = QMainWindow()
    mainWindow.setCentralWidget(mainWidget)
    mainWindow.setWindowTitle("Demo App")
    mainWindow.resize(300, 300)
    mainWindow.show()
    app.exec()

Just add a stretch to the bottom of the layout (this is only possible for boxed layout):

class AccountListWidget(QWidget):
    def __init__(self, data: List[dict], parent=None):
        # ...
        self.main_layout.addStretch()

If you need to do something like this on a grid layout, you can add a QSpacerItem or a single empty QWidget with its size policy set to expanded:

    spacer = QtWidgets.QWidget()
    spacer.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanded)
    gridLayout.addWidget(spacer, gridLayout.rowCount(), 0)

Another solution is to set the size policy to the container (instead of adding the stretch):

class AccountListWidget(QWidget):
    def __init__(self, data: List[dict], parent=None):
        # ...
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)

A couple of suggestions:

  • avoid using unnecessary container widgets: Your AccountWidget only contains a QGroupBox, so you should probably just subclass from QGroupBox instead;
  • grid layouts, as most things, use 0-based indexes, so your widgets should be added starting from row and column 0 (not 1); if you're doing that to add margins, use layout.setContentsMargins ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM