QListWidget 复选框与项目选择同步
QListWidget checkbox sync with item selection
我在尝试设置 QListWidget 时遇到了一个奇怪的问题,我可以在其中单击 select 项目的复选框。我目前编写的代码不会使这种模式保持一致。喜欢下面的table。
例如,当我单击“苹果”复选框时,我希望“苹果”项会被 selected,但有时“橙色”会被删除selected。有时它起作用了我想要的方式,但它是不可预测的table。我已经阅读了几乎所有关于这个问题的 Whosebug 线程,但是 none 解决了它。
我的环境是MacBig 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()
更新:
第一个答案非常复杂,因为我深入挖掘了更多东西要学习。最后,我找到了一个更容易实施的替代解决方案。我 post 核心部分供将来可能需要它的任何人使用。
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"))
据我了解,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)
我在尝试设置 QListWidget 时遇到了一个奇怪的问题,我可以在其中单击 select 项目的复选框。我目前编写的代码不会使这种模式保持一致。喜欢下面的table。
例如,当我单击“苹果”复选框时,我希望“苹果”项会被 selected,但有时“橙色”会被删除selected。有时它起作用了我想要的方式,但它是不可预测的table。我已经阅读了几乎所有关于这个问题的 Whosebug 线程,但是 none 解决了它。 我的环境是MacBig 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()
更新: 第一个答案非常复杂,因为我深入挖掘了更多东西要学习。最后,我找到了一个更容易实施的替代解决方案。我 post 核心部分供将来可能需要它的任何人使用。
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"))
据我了解,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)