无法通过自定义小部件更改可检查QListViewItem的状态

6 投票
2 回答
3918 浏览
提问于 2025-04-16 08:54

我有一个 QListWidget,想在里面添加一些带有自定义小部件的项目:

        listWidget = QListWidget()
        item = QListWidgetItem()
        item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
        item.setCheckState(Qt.Unchecked)
        listWidget.addItem(item)
        widget = MyLabelAndPushButton()
        item.setSizeHint(widget.sizeHint())
        listWidget.setItemWidget(item, widget)

正如名字所示,MyLabelAndPushButton 只是一个小部件,它里面有一个 QLabel 和一个 QPushButton,都是放在一个布局里的。问题是,我无法使用出现在列表小部件旁边的复选框。看起来一切正常,但我点击它时什么也不会发生。如果我去掉那行 setItemWidget 的代码,它就能正常工作。我到底哪里做错了呢?

补充:

我在 bugreports.qt.io/browse/QTBUG-16386 上报告了这个问题,但得到的回复是“这个 API 不是为了你想做的事情设计的”和“如果你想显示自定义小部件,使用 QListView 并子类化 QItemDelegate。”所以显然这不是一个 bug,只是这个 API 无法处理的事情。

2 个回答

1

QListWidget::setItemWidget的文档上说:

这个函数应该只用来显示列表项中的静态内容。如果你想显示自定义的动态内容或者实现一个自定义的编辑器小部件,应该使用QListView并且继承QItemDelegate。

这里提到的“静态内容”,我想是指那些不能互动的内容,这说明在使用QListWidget时有这个已知的限制。

2

我不太明白为什么列表项在设置小部件时不想改变状态。我想解决这个问题的方法可以是,在你的小部件中添加一个复选框,或者连接到列表小部件的itemClicked信号,然后在那儿重置项的状态。请看看下面的例子是否对你有帮助:

import sys
from PyQt4 import QtGui, QtCore

class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        listWidget = QtGui.QListWidget()

        item = QtGui.QListWidgetItem()
        item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
        item.setCheckState(QtCore.Qt.Unchecked)
        listWidget.addItem(item)

        widget = QtGui.QCheckBox('test')
        item.setSizeHint(widget.sizeHint())
        listWidget.setItemWidget(item, widget)

        listWidget.itemClicked.connect(self.on_listWidget_itemClicked)

        self.setCentralWidget(listWidget)

    def on_listWidget_itemClicked(self, item):
        if item.listWidget().itemWidget(item) != None: 
            if item.checkState() == QtCore.Qt.Checked:
                item.setCheckState(QtCore.Qt.Unchecked)
            else:
                item.setCheckState(QtCore.Qt.Checked)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

希望这能帮到你,祝好

撰写回答