1

当我尝试设置 QListWidget 时遇到了一个奇怪的问题,我可以在其中单击复选框以选择项目。我编写的当前代码不会使这种模式保持一致。如下表所示。

在此处输入图像描述

例如,当我单击“apple”复选框时,我希望“apple”项目会被选中,但有时会取消选中“橙色”。有时它会按我想要的方式工作,但它是不可预测的。我已经阅读了几乎所有StackOverflow 线程处理了这个问题,但是没有一个能解决,我的环境是 Mac Big Sur,Python3.7.9,PySide6 6.2.0。

我下面有一个MVE,有人可以帮我看看吗?欣赏它。卡在这里很久了。

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


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        self.list = QListWidget(self)
        self.list.setIconSize(QSize(12, 12))

        self.list.setSelectionMode(QAbstractItemView.MultiSelection)
        self.list.itemSelectionChanged.connect(
            self.on_selection_changed)
        self.list.itemChanged.connect(self.on_checkbox_clicked)

        # Set the central widget of the Window.
        self.setCentralWidget(self.list)

        for sheet in ['apple', 'orange', 'banana', 'pearl']:
            item = QListWidgetItem(sheet)
            self.list.addItem(item)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Unchecked)

    def on_checkbox_clicked(self, item):
        print(item.text())
        print(item.checkState())
        if item.checkState() is Qt.CheckState.Checked:
            item.setSelected(True)
            # self.list.setCurrentItem(
            #     item, QItemSelectionModel.Select)
            print(f'select: {item.text()}')
        else:
            item.setSelected(False)
            # self.list.setCurrentItem(
            #     item, QItemSelectionModel.Deselect)
            print(f'unselect: {item.text()}')

    def on_selection_changed(self):
        self.list.blockSignals(True)
        for index in range(self.list.count()):
            item = self.list.item(index)
            if item.isSelected():
                item.setCheckState(Qt.CheckState.Checked)
            elif not item.isSelected():
                item.setCheckState(Qt.CheckState.Unchecked)
        self.list.blockSignals(False)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

更新:第一个答案非常复杂,因为我更深入地了解还有更多要学习的东西。最后,我找到了一个更容易实现的替代解决方案。我为将来可能需要它的任何人发布核心部分。

listwidget = QListWidget()
listwidget.setSelectionMode(QAbstractItemView.MultiSelection)

listwidget.itemSelectionChanged.connect(self.on_selection_changed)

def on_selection_changed()
    for index in range(listwidget.count()):
        item = listwidget.item(index)
        if item.isSelected():
            item.setIcon(QIcon("path/to/your/check_icon.png"))
        else:
            item.setIcon(QIcon("path/to/your/uncheck_icon.png"))
4

1 回答 1

1

据我了解,OP希望同步,如果用户选择了一个项目,那么它就会被选中,反之亦然。考虑到这一点,一个可能的解决方案是消除委托对复选框矩形所做的验证。另一方面,用户也可以使用键盘更改复选框的状态,因此可能的解决方案是使用 itemChange 信号来更新选择的状态。

class Delegate(QStyledItemDelegate):
    def editorEvent(self, event, model, option, index):
        last_state = index.data(Qt.ItemDataRole.CheckStateRole)
        ret = super().editorEvent(event, model, option, index)
        if event.type() in (
            QEvent.Type.MouseButtonPress,
            QEvent.Type.MouseButtonDblClick,
        ):
            return False
        elif event.type() == QEvent.Type.MouseButtonRelease and last_state is not None:
            flags = model.flags(index)
            if flags & Qt.ItemFlag.ItemIsUserTristate:
                state = (last_state + 1) % 3
            else:
                state = (
                    Qt.CheckState.Unchecked
                    if last_state == Qt.CheckState.Checked
                    else Qt.CheckState.Checked
                )
            model.setData(index, state, Qt.ItemDataRole.CheckStateRole)
            return False
        return ret


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        self.listwidget = QListWidget(self)
        self.listwidget.setIconSize(QSize(12, 12))
        self.listwidget.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
        self.setCentralWidget(self.listwidget)
        self.listwidget.setItemDelegate(Delegate(self.listwidget))
        self.listwidget.itemChanged.connect(self.handle_itemChanged)

        for sheet in ["apple", "orange", "banana", "pearl"]:
            item = QListWidgetItem(sheet)
            self.listwidget.addItem(item)
            item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
            item.setCheckState(Qt.CheckState.Unchecked)

    def handle_itemChanged(self, item):
        item.setSelected(item.checkState() == Qt.CheckState.Checked)
于 2021-11-03T17:12:31.597 回答