PySide2 QListWidgetItem自定义部件窗口Resize时高度不收缩问题修复
QListWidget自定义部件随窗口调整自动适配高度的解决方案
问题场景
使用PySide2开发时,为QListWidget添加自定义部件后,主对话框调整大小,QListWidgetItem无法自动调整高度以适配可用空间,出现大量空白间隙。

解决方法
问题核心是QListWidgetItem的sizeHint不会随自定义部件宽度变化自动更新,需通过以下调整实现动态适配:
1. 改造自定义部件NoteWidget
- 移除
self.uiDescription.adjustSize(),避免固定描述标签高度 - 重写
resizeEvent,在部件宽度变化时重新计算布局,并发送自定义信号通知列表项更新尺寸 - 调整布局约束为
SetMinAndMaxSize,允许部件根据内容动态调整大小
2. 监听QListWidget宽度变化
在主窗口中,监听QListWidget的尺寸变化事件,遍历所有列表项,触发自定义部件重新计算尺寸并更新item的sizeHint
修改后的完整代码
import os import sys from PySide2 import QtCore, QtGui, QtWidgets class NoteWidget(QtWidgets.QWidget): sizeChanged = QtCore.Signal() # 自定义尺寸变化信号 def __init__(self, noteItem): super(NoteWidget, self).__init__() self.setStyleSheet('border: 1px solid red;') # 控件初始化 self.uiCategory = QtWidgets.QLabel() self.uiCategory.setTextFormat(QtCore.Qt.PlainText) self.uiCategory.setStyleSheet('font-family: Arial; font-weight: bold; font-size: 14px;') self.uiCategory.setText(noteItem['category']) self.uiDescription = QtWidgets.QLabel() self.uiDescription.setWordWrap(True) self.uiDescription.setText(noteItem['description']) # 布局设置 self.mainLayout = QtWidgets.QVBoxLayout() self.mainLayout.setContentsMargins(10,10,10,10) self.mainLayout.setSpacing(0) self.mainLayout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) self.mainLayout.setAlignment(QtCore.Qt.AlignTop) self.mainLayout.addWidget(self.uiCategory) self.mainLayout.addWidget(self.uiDescription) self.setLayout(self.mainLayout) def resizeEvent(self, event): super().resizeEvent(event) self.mainLayout.invalidate() # 强制布局重新计算 self.sizeChanged.emit() # 发送尺寸变化信号 class FileNotesDialog(QtWidgets.QMainWindow): def __init__(self, parent=None): super(FileNotesDialog, self).__init__(parent) self.uiList = QtWidgets.QListWidget() self.uiList.setSpacing(0) self.uiList.setFocusPolicy(QtCore.Qt.NoFocus) self.uiList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) self.uiList.verticalScrollBar().setSingleStep(10) self.uiList.setUniformItemSizes(False) self.uiList.setResizeMode(QtWidgets.QListWidget.Adjust) self.uiList.setSizeAdjustPolicy(QtWidgets.QListWidget.AdjustToContents) self.uiList.setSelectionMode(QtWidgets.QListView.ExtendedSelection) self.mainLayout = QtWidgets.QVBoxLayout() self.mainLayout.setSpacing(6) self.mainLayout.setContentsMargins(6, 6, 6, 6) self.mainLayout.addWidget(self.uiList) self.mainWidget = QtWidgets.QWidget() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.populateNotes() def resizeEvent(self, event): super().resizeEvent(event) self.updateListItemSizes() # 窗口调整时更新所有列表项尺寸 def updateListItemSizes(self): for index in range(self.uiList.count()): item = self.uiList.item(index) widget = self.uiList.itemWidget(item) if widget: widget.adjustSize() item.setSizeHint(widget.sizeHint()) def populateNotes(self): self.uiList.clear() notes = [ {'category': 'Misc', 'description': 'Here is a simple reminder'}, {'category': 'Today', 'description': 'Here is a longer reminder that will use wordwrap because it is a really long description provided by the user for reading when they have time. It should not be ignored.'}, {'category': 'Notes', 'description': 'Here is another simple reminder for you.'}, {'category': 'General', 'description': 'I think this will fix the problem if you have to time implement this when you are working today.'} ] for obj in notes: nw = NoteWidget(obj) lwi = QtWidgets.QListWidgetItem() self.uiList.addItem(lwi) self.uiList.setItemWidget(lwi, nw) # 连接尺寸变化信号,实时更新item尺寸 nw.sizeChanged.connect(lambda item=lwi, widget=nw: item.setSizeHint(widget.sizeHint())) lwi.setSizeHint(nw.sizeHint()) def main(): app = QtWidgets.QApplication(sys.argv) ex = FileNotesDialog() ex.resize(500,700) ex.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
关键改动说明
- NoteWidget中添加
sizeChanged信号,确保宽度变化时实时通知列表项更新尺寸 - 移除固定高度的
adjustSize()调用,让描述标签随宽度自动换行调整高度 - 主窗口监听resize事件,批量更新所有列表项的尺寸
- 将QListWidget的
sizeAdjustPolicy改为AdjustToContents,确保列表自身适配内容变化
内容的提问来源于stack exchange,提问作者JokerMartini
相关产品推荐
相关产品推荐

