效果预览
直接看图,效果展现为在Checkbox
后跟随图标实现友好的界面交互且可勾选
核心代码说明
控件初始化
类的构造函数__init__
在窗口中创建了一个垂直布局QVBoxLayout
,并在布局内添加了一个QListView
用于展示可勾选的列表项(通过CheckableItemModel
和CheckBoxDelegate
来实现相关的数据模型与委托逻辑)
def __init__(self):
super().__init__()
self.setWindowTitle("QCheckBoxIcon Demo")
__desktop = QDesktopWidget()
__screen_width = __desktop.screenGeometry().width()
__screen_height = __desktop.screenGeometry().height()
self.setGeometry(int(__screen_width * 0.25),
int(__screen_height * 0.25),
__screen_width // 2,
__screen_height // 2)
self._layout = QVBoxLayout()
self._list_view = QListView()
self._model = CheckableItemModel()
delegate = CheckBoxDelegate()
self._list_view.setModel(self._model)
self._list_view.setItemDelegate(delegate)
self._layout.addWidget(self._list_view, alignment=Qt.AlignTop) # 可不对齐
self.setLayout(self._layout)
self._model = CheckableItemModel()
创建一个CheckableItemModel
对象,这个类是自定义的数据模型,用于管理可勾选列表项的数据,并按照PyQt5的数据模型机制与视图QListView
进行交互,提供数据展示、更新等功能delegate = CheckBoxDelegate()
创建一个CheckBoxDelegate
对象,用于处理列表视图QListView
中列表项的委托逻辑,用于编辑勾选状态的勾选框QCheckBox
、设置其初始数据以及将编辑后的数据更新回数据模型等操作self._list_view.setItemDelegate(delegate)
把CheckBoxDelegate
对象设置给QListView
作为其委托,用于处理列表项的特定编辑和展示逻辑,使得QListView
在处理可勾选列表项时能按照自定义的委托逻辑进行操作
自定义勾选框模型
CheckableItemModel
类继承自QAbstractListModel
,是在PyQt5框架下用于为列表视图(提供自定义数据模型的类。它旨在管理一系列具有可勾选特性、可能带有图标的列表项,使得视图能够根据其提供的数据和规则来展示相应的界面元素,并处理用户与这些元素交互时的数据更新等操作,常用于构建如配置选项列表、文件筛选列表等具有可勾选功能的界面场景
class CheckableItemModel(QAbstractListModel):
"""
图标勾选框模型
- items 项列表
"""
def __init__(self, items = None):
super().__init__()
if items is None:
self._items = []
else:
self._items = items
def rowCount(self, parent=QModelIndex(), *args, **kwargs):
return len(self._items)
def data(self, index, role=Qt.DisplayRole):
"""
- Qt.DisplayRole 描述
- Qt.CheckStateRole 勾选状态
- Qt.DecorationRole 图标
"""
if role == Qt.DisplayRole:
return self._items[index.row()].name()
elif role == Qt.CheckStateRole:
if self._items[index.row()].checkbox():
return Qt.Checked if self._items[index.row()].checked_status() else Qt.Unchecked
else:
return None
elif role == Qt.DecorationRole:
return self._items[index.row()].icon()
return None
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.CheckStateRole:
self._items[index.row()].checked_set(value == Qt.Checked)
self.dataChanged.emit(index, index, [role])
return True
return False
def flags(self, index):
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if self._items[index.row()].checkbox():
flags |= Qt.ItemIsUserCheckable
return flags
def addItem(self, checkable_item):
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self._items.append(checkable_item)
self.endInsertRows()
rowCount
重写了父类QAbstractListModel
的rowCount
方法。这个方法的作用是告知视图数据模型中包含的行数,也就是列表项的数量data
方法根据传入的索引index和指定的角色role来返回相应的数据内容,供视图展示使用Qt.DisplayRole
视图期望获取用于显示的文本信息;Qt.CheckStateRole
视图期望获取该项的勾选状态信息;Qt.DecorationRole
图期望获取用于装饰显示的图标信息setData
用于处理视图传来的对数据的修改请求,根据传入的索引index、新的值value以及角色role来更新数据模型中的相应数据,并反馈更新是否成功。当role为Qt.CheckStateRole
时,表示是对勾选状态的修改操作。通过索引获取对应的列表项,然后调用其checked_set
方法,将传入的value与Qt.Checked
进行比较,根据比较结果来更新列表项的勾选状态。之后,通过self.dataChanged.emit()
发出信号,通知视图对应的数据项在勾选状态这一角色下的数据已发生改变,触发视图进行界面更新,最后返回True表示数据更新成功flags
方法用于设置每个列表项对应的标志位,以告知视图该项具有哪些交互特性。Qt.ItemIsEnabled
标志,表示该项是启用状态,用户可以与之交互,比如鼠标悬停、点击等操作;Qt.ItemIsSelectable
标志,表示该项可以被选择,Qt.ItemIsUserCheckable
标志,表示该项可由用户进行勾选操作addItem
方法用于向数据模型中添加新的列表项,调用self.beginInsertRows
方法,传入一个QModelIndex
以及当前的行数,这一步操作是通知视图即将要插入新的行数据,让视图做好相应的准备,比如更新内部的数据结构、布局等,以正确响应后续数据的变化。self.endInsertRows
方法,告知视图行插入操作已经完成,触发视图进行最终的界面更新,确保新添加的列表项能够正确地显示在视图中
勾选框委托
CheckBoxDelegate
类继承自 QStyledItemDelegat
e,在 PyQt5 图形用户界面编程框架中,委托类用于自定义视图中各个数据项的显示和编辑行为。这个特定的类主要聚焦于处理列表项中与复选框QCheckBox
相关的编辑逻辑,包括创建用于编辑的复选框、设置其初始状态以及将编辑后的状态回写到数据模型中,从而实现了列表项中可勾选功能的完整交互流程,确保用户对复选框的操作能够正确地反映在数据层面,并与对应的视图展示相匹配
class CheckBoxDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
if index.data(Qt.CheckStateRole) is not None:
check_box = QCheckBox(parent)
check_box.stateChanged.connect(lambda state, idx=index: self.commitData.emit(check_box))
return check_box
else:
return None
def setEditorData(self, editor, index):
value = index.data(Qt.CheckStateRole)
if value is not None:
editor.setCheckState(value)
def setModelData(self, editor, model, index):
if editor is not None:
model.setData(index, editor.checkState(), Qt.CheckStateRole)
createEditor
方法的主要职责是为视图中的可编辑数据项创建对应的编辑器部件。当对应的数据项需要展示和编辑复选框(时,就创建一个 QCheckBox作为编辑器
– 首先,通过index.data(Qt.CheckStateRole)
获取指定索引inde
x 对应的数据项的勾选状态角色数据。如果这个值不为None
,意味着该项在视图中应该呈现出可勾选的复选框形式,并且可以进行编辑操作
– 接着,创建一个QCheckBox
对象,并将其传递的paren
t 参数作为其父部件,这样可以确保它在视图的相应位置正确显示,并且遵循父部件的布局和显示规则
– 然后,将创建好的QCheckBox
的stateChanged
信号连接到一个匿名函数。这个匿名函数捕获复选框改变后的状态值以及当前的index
,并在内部调用self.commitData.emit(check_box)
。commitData.emit
方法是委托类中用于通知数据模型更新数据的重要机制,当复选框的状态改变时,通过这个信号发射,触发后续的数据更新操作,将新的状态写回到数据模型中setEditorData
方法用于设置QCheckBox
的初始数据,确保编辑器在显示给用户进行编辑操作前,其状态与对应的数据项的当前勾选状态一致
– 首先,通过index.data(Qt.CheckStateRole)
获取指定索引index
对应的数据项的当前勾选状态值,这个值可能是Qt.Checked
、Qt.Unchecked
或者Qt.PartiallyChecked
对应的枚举值
– 然后,调用QCheckBox
的setCheckState
方法,将获取到的状态值赋给QCheckBox
,使其初始显示的勾选状态与数据模型中对应的数据项的状态相匹配,这样用户看到的就是准确反映当前数据状态的复选框外观setModelData
方法的作用是在QCheckBox
的状态发生改变后,将改变后的状态数据写回到数据模型中,以实现数据的更新和同步,保证视图与数据模型之间的数据一致性
– 如果可编辑的复选框并且其状态已经发生了改变,此时调用数据模型的setData
方法,传入当前的索引index
、QCheckBox
的当前勾选状态(通过editor.checkState 获取
)以及角色Qt.CheckStateRole
,告知数据模型对应索引的数据项在勾选状态方面发生了改变,需要更新相应的数据,使得数据模型能够根据新的勾选状态来保存和管理数据,进而触发视图根据更新后的数据进行重新展示等后续操作,保持整个界面与数据的同步性
调用演示
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = ApplicationCheckableItem()
widget.add_item(CheckableItem("Item 1 checkbox", True, "usb.png"))
widget.add_item(CheckableItem("Item 2 no checkbox", False, "usb.png", checkbox=False))
widget.add_item(CheckableItem("Item 3 checkbox", False, "usb.png"))
widget.show()
sys.exit(app.exec_())
完整代码获取
完整代码请从我的资源获取