我通过QListWidget实现了一个可选列表,然后我发现如果我想改变checkbox的状态,只能通过点击checkbox来改变。
但是我也想通过点击Item来切换复选框状态,所以我将QListWidget的ItemClicked信号连接到一个新的槽函数来实现。
我后来发现与该项目关联的复选框的状态只能通过单击该项目来更改,而不是复选框本身。
我很好奇这个过程中发生了什么,以及我应该做什么来实现我的目标,即可以通过单击复选框或项目本身来切换复选框的状态。打击是我的代码:
class Item(QListWidgetItem):
def __init__(self):
super().__init__()
# self.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled)
self.setCheckState(Qt.CheckState.Unchecked)
self.setToolTip("double click edit")
class MainWindow(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.add_btn = QPushButton("add")
self.select_all = QPushButton("select all")
self.del_btn = QPushButton("delete")
btn_layout = QHBoxLayout()
btn_layout.addWidget(self.select_all)
btn_layout.addWidget(self.add_btn)
btn_layout.addWidget(self.del_btn)
self.list_widget = QListWidget()
self.list_widget.setSelectionMode(QListWidget.SelectionMode.ContiguousSelection)
self.list_widget.setAlternatingRowColors(True)
layout.addLayout(btn_layout)
layout.addWidget(self.list_widget)
self.setLayout(layout)
self.add_btn.clicked.connect(self.addItem)
# self.list_widget.itemClicked.connect(self.itemClickedEvent)
def addItem(self):
item = Item()
item.setText("test")
self.list_widget.addItem(item)
def itemClickedEvent(self, item: QListWidgetItem):
pass
if item.checkState() == Qt.CheckState.Checked:
item.setCheckState(Qt.CheckState.Unchecked)
else:
item.setCheckState(Qt.CheckState.Checked)
这是因为,当尝试切换项目的复选框时,它也被单击,因此检查状态实际上改变了两次。
您可以通过连接到
itemChanged
信号来验证这一点:
self.list_widget.itemChanged.connect(lambda i: print(i.checkState()))
当您单击检查指示器时,信号会发出两次,第一次是新的检查状态,第二次是以前的状态,由您的函数设置。
一个可能的解决方案是使该项目不可由用户检查:
class Item(QListWidgetItem):
def __init__(self):
super().__init__()
self.setCheckState(Qt.CheckState.Unchecked)
self.setFlags(self.flags() & ~Qt.ItemFlag.ItemIsUserCheckable)
self.setToolTip("double click edit")
不幸的是,这有一个缺点,即无法使用键盘切换状态。
作为替代方案,您可以使用自定义委托,并使其忽略在检查指示符矩形内发生的鼠标左键释放。在这种情况下,您必须不更改项目标志,如上所述。
class Delegate(QStyledItemDelegate):
_checkFlags = Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsUserCheckable
def editorEvent(self, event, model, option, index):
if (
event.type() == event.Type.MouseButtonRelease
and event.button() == Qt.MouseButton.LeftButton
and index.flags() & self._checkFlags == self._checkFlags
and option.state & QStyle.State.State_Enabled
):
opt = QStyleOptionViewItem(option)
self.initStyleOption(opt, index)
checkRect = option.widget.style().subElementRect(
QStyle.SubElement.SE_ItemViewItemCheckIndicator, opt, option.widget)
if event.pos() in checkRect:
return False
return super().editorEvent(event, model, option, index)
...
self.list_widget.setItemDelegate(Delegate(self.list_widget))