带有 setWordWrap(True) 的 QLabels 在放置在 QListWidget 中时不会垂直调整大小,即使 resizeMode 已设置为 Adjust 将尺寸政策设置为 Expanding使用 sizeHint 中的 QLabel 设置 QListWidgetItem 的大小提示

问题描述

如何将带有 QLabelsetWordWrap(True) 放在 QListWidget/QListView 中,以便 QLabel 在父小部件的大小是否已调整?

当我尝试这样做时,我遇到了 QLabels 没有获得正确高度的问题(参见下面的示例 2)

我正在使用

  • Python:3.8.5
  • PyQt5:5.15.2

示例 1:使用 QVBoxLayout

为了展示我想要完成的事情,我想首先展示一个示例,其中我只是将 QLabel 添加到 QVBoxLayout

这如我所愿:如果我水平调整(主)窗口的大小,带有换行文本的 QLabel 将垂直占用更多空间

example 1

import sys
from PyQt5.QtWidgets import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setMinimumHeight(150)
        self.main_widget = QWidget()
        self.setCentralWidget(self.main_widget)
        vbox = QVBoxLayout()
        self.main_widget.setLayout(vbox)

        label_1 = QLabel("label_1")
        vbox.addWidget(label_1)
        label_1.setStyleSheet("*{background-color: #f0f000;}")

        label_2 = QLabel("[wrapped] label_2 Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
        vbox.addWidget(label_2)
        label_2.setStyleSheet("*{background-color: #00f0f0;}")
        label_2.setWordWrap(True)


app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()

示例 2:使用 QListWidget

这是我遇到问题的代码:运行此代码不会为带有换行文本的 Qlabel 提供任何额外空间

(示例中使用了 QListWidget 而不是 QListView 但从我所看到的 - 以及我对这些类的理解 - 应该没有区别)

请注意,resizeMode property 已设置为 QListView.Adjust

example 2

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.list_widget = QListWidget()
        self.setCentralWidget(self.list_widget)
        self.list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.list_widget.setResizeMode(QListView.Adjust)  # <-----
        self.list_widget.setUniformItemSizes(False)  # -should already be false,but just in case
        self.list_widget.setWordWrap(True)  # -AFAIK this should only effect text that is put directly into QListWidgetItems,but just in case

        item_1_text_str = f"Item number 1"
        lwi_item_1 = QListWidgetItem(self.list_widget)
        self.list_widget.addItem(lwi_item_1)
        item_1_widget_qlabel = QLabel(item_1_text_str)
        item_1_widget_qlabel.setStyleSheet("*{background-color: #f0f000;}")
        self.list_widget.setItemWidget(lwi_item_1,item_1_widget_qlabel)

        item_2_text_str = "[wrapped] label_2 Lorem ipsum dolor sit amet,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
        lwi_item_2 = QListWidgetItem(self.list_widget)
        self.list_widget.addItem(lwi_item_2)
        item_widget_2_qlabel = QLabel(item_2_text_str)
        item_widget_2_qlabel.setWordWrap(True)  # <-------
        item_widget_2_qlabel.setStyleSheet("*{background-color: #00f0f0;}")
        self.list_widget.setItemWidget(lwi_item_2,item_widget_2_qlabel)


app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()

我尝试了什么

将尺寸政策设置为 Expanding

通常策略设置为 MinimumExpanding,所以我认为 Expanding 会更好,因为 Expanding 包含 Shrink 标志

在上面的代码示例 2 中,它看起来像这样:

    item_widget_2_qlabel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)

这并没有帮助

使用 sizeHint 中的 QLabel 设置 QListWidgetItem 的大小提示

如果在 __init__ 中完成:

lwi_item_2.setSizeHint(item_widget_2_qlabel.sizeHint())

这样做的问题是它只会设置一次大小提示,然后sizeHint就会卡住,所以带回绕文本的QLabel无法垂直展开或收缩

或者使用此代码,以便在调整主窗口大小时更新 sizeHint:

class MainWindow(QMainWindow):
    [...]

def resizeEvent(self,a0: QResizeEvent) -> None:
    super().resizeEvent(a0)
    row = 0
    while row < self.list_widget.count():
        lwi_item = self.list_widget.item(row)
        item_widget = self.list_widget.itemWidget(lwi_item)
        widget_size_hint = item_widget.sizeHint()
        lwi_item.setSizeHint(widget_size_hint)  # <--------
        row += 1

令人惊讶的是,使用此代码时的结果是相同的:QLabel 的垂直大小没有改变

解决方法

在编写此问题时,我能够在 QLabel.heightForWidth 子类的重写 resizeEvent 中使用 QListWidget 找到解决方案

虽然这不是我所希望的(我曾希望我错过了一些简单的东西,以便解决方案更优雅)。 如果有人有比这更好的解决方案,请分享!

无论如何这是我用来让它工作的代码

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class ListWidget(QListWidget):
    def __init__(self):
        super().__init__()
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        """
        self.list_widget.setResizeMode(QListView.Adjust)
        -this is not needed with this solution. (Maybe because it only effects QListWidgetItems?)
        """

    def resizeEvent(self,a0: QResizeEvent) -> None:
        super().resizeEvent(a0)
        row = 0
        while row < self.count():
            lwi_item = self.item(row)
            item_widget = self.itemWidget(lwi_item)
            if isinstance(item_widget,QLabel) and hasattr(item_widget,"wordWrap") and item_widget.wordWrap():
                width_int = self.width() - self.contentsMargins().left() - self.contentsMargins().right()
                height_hfw_int = item_widget.heightForWidth(width_int)  # <--------
                widget_size_hint = QSize(width_int,height_hfw_int)
                lwi_item.setSizeHint(widget_size_hint)
            row += 1


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.list_widget = ListWidget()
        self.setCentralWidget(self.list_widget)

        lwi_item_1 = QListWidgetItem(self.list_widget)
        self.list_widget.addItem(lwi_item_1)
        item_1_widget_qlabel = QLabel("Item number 1")
        item_1_widget_qlabel.setStyleSheet("*{background-color: #f0f000;}")
        self.list_widget.setItemWidget(lwi_item_1,item_1_widget_qlabel)

        lwi_item_2 = QListWidgetItem(self.list_widget)
        self.list_widget.addItem(lwi_item_2)
        item_2_html_rich_str = "<span style='font-size:12pt'>Listen,strange women lyin in ponds distributin swords is no basis for a system of government.</span><br><span>Supreme executive power derives from a mandate from the masses,not from some farcical aquatic ceremony.</span>"
        item_2_markdown_str = "## Listen,strange women lyin in ponds distributin swords is no basis for a system of government.\n\nSupreme executive power derives from a mandate from the masses,not from some farcical aquatic ceremony."
        item_2_text_str = "Listen,not from some farcical aquatic ceremony."
        item_widget_2_qlabel = QLabel(item_2_html_rich_str)
        item_widget_2_qlabel.setTextFormat(Qt.RichText)  # Qt.RichText,Qt.MarkdownText,Qt.PlainText
        item_widget_2_qlabel.setWordWrap(True)  # <-------
        item_widget_2_qlabel.setStyleSheet("*{background-color: #00f0f0;}")
        self.list_widget.setItemWidget(lwi_item_2,item_widget_2_qlabel)


app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...