问题描述
如何将带有 QLabel
的 setWordWrap(True)
放在 QListWidget
/QListView
中,以便 QLabel
在父小部件的大小是否已调整?
当我尝试这样做时,我遇到了 QLabels 没有获得正确高度的问题(参见下面的示例 2)
我正在使用
- Python:3.8.5
- PyQt5:5.15.2
示例 1:使用 QVBoxLayout
为了展示我想要完成的事情,我想首先展示一个示例,其中我只是将 QLabel
添加到 QVBoxLayout
这如我所愿:如果我水平调整(主)窗口的大小,带有换行文本的 QLabel
将垂直占用更多空间
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
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_()