如何调整 QLabel 的大小以适应 QScrollArea 中的内容

How to resize QLabels to fit contents in QScrollArea

此问题特定于 PyQt5,但 C++ Qt5 答案也很好。

在固定宽度和可变高度的 QScrollArea 中,我有一个包含 QLabelQVBoxLayout。这些 QLabelssetWordWrap(True) 并且包含的​​文本可能比 QScrollArea 的固定宽度长。当 QLabel 中的文本换行到 ~4 行时,一切正常,但是当 QLabel 需要更多时,它无法继续增加 QLabel 的高度,并削减关闭顶部和底部的一些文本。

This answer 试图解决本质上相同的问题,其中涉及将 QLabel 的垂直 sizePolicy() 设置为 MinimumExpanding,而这个 技术上 有效,但它会强制 QLabels 尝试填充整个 QScrollArea 视口,如果视口尚未被 QLabel 填充。

这是当前未将 sizePolicy 设置为 MinimumExpanding 的样子(注意第一个 QLabel):

下面是将 MinimumExpanding 设置为 QLabel 的垂直尺寸策略时的样子(看起来很棒...):

但是当滚动区域只有几个 QLabels 时会导致这种行为,这是不可接受的行为,因为这将是一项 "comments" 服务,人们可以在其中post 他们的纯文本问题:

有没有人有解决此问题的方法,或遇到过类似的问题?

作为参考,这是我的一些代码:

class NewsList(QtWidgets.QScrollArea):
    def __init__(self, parent=None):
        super(NewsList, self).__init__(parent)
        self.setMaximumWidth(200)
        self.setWidgetResizable(True)

        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(5)
        layout.setAlignment(QtCore.Qt.AlignTop)
        self.news_widget = QtWidgets.QFrame()
        self.news_widget.setStyleSheet("""
            QFrame {
                background-color: #ffffff;
            }
        """)
        self.news_widget.setLayout(layout)
        self.setWidget(self.news_widget)
        self.fetch_news()

    def fetch_news(self):
        self.append_message('DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d')
        self.append_message('DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d')
        self.append_message('DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d')
        self.append_message('DSADAISH ')
        self.append_message('DSADAISH ')
        self.append_message('DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d')
        self.append_message('DSADAISH dshadbsasdsadh sd ashd sah dsha dhsa dsa d')

    def append_message(self, text):
        new_item = QtWidgets.QLabel(text)
        new_item.setWordWrap(True)
        new_item.setStyleSheet("""
            QLabel {
                padding: 4px;
                border: 1px solid black;
                background-color: #ffffff;
            }
        """)

这可以通过使用包含新闻项的布局的 addStretch 方法非常简单地解决:

class NewsList(QtWidgets.QScrollArea):
    def __init__(self, parent=None):
        ...    
        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(5)
        layout.setAlignment(QtCore.Qt.AlignTop)
        # add a stretchable space to the bottom of the layout
        layout.addStretch(1)

    def append_message(self, text):
        ...
        # set the size policy of the label
        new_item.setSizePolicy(
            QtWidgets.QSizePolicy.Preferred,
            QtWidgets.QSizePolicy.MinimumExpanding)
        # insert the label before the spacer        
        layout = self.news_widget.layout()
        layout.insertWidget(layout.count() - 1, new_item)

spacer 将标签向上推,这会阻止它们拉伸以占用可用的 space。使用 addStretchstretch-factor 参数可确保 spacer 始终优先于布局中的其他项目。