一、概述
QListView理论上可以和所有QAbstractItemModel派生的类如QStringListModel、QDirModel、QFileSystemModel、QStandardItemModel等对接,但QListView实际上能展示的数据仅一列,对于复杂的树形层次使用Model使用QListView来展现意义不大。本节通过几个简单代码案例来阐述QListView/Model开发的过程。
二、QListView/QStringListModel
2.1、QStringListModel介绍
QStringListModel是Qt提供的一个已经实现QAbstractItemModel相关接口的Model,适合于展示一系列字符串的简单视图如QListView对象和QComboBox对象。
QStringListModel提供了所有可编辑模型的标准函数,将字符串列表中的数据存储为一个一列多行的模型。
使用index(int row, int column = 0, QModelIndex parent = QModelIndex())函数获取与项对应的模型索引,使用flags(QModelIndex index)获取项标志;使用data()函数读取项数据,并使用setData()写入项数据,使用rowCount()函数访问模型数据的行数。
该模型可以用现有的字符串列表来构造,或者可以用setStringList()函数来设置字符串。字符串也可以用insertRows()函数以通常的方式插入,并用removeRows()删除。字符串列表的内容可以使用stringList()函数检索。
2.2、使用QStringListModel作为QListView的Model
使用QStringListModel作为QListView的Model的方法非常简单,先创建QStringListModel实例对象,如果数据未存储到Model中则将数据存储到Model,然后再将QListView对象的Model设置为刚创建的Model实例。步骤如下:
2.2.1、 创建QStringListModel实例对象
实例对象创建有两种方法:
- 创建无数据的Model
语法为:QStringListModel(QObject parent = None) - 创建Model同时初始化数据
语法为:QStringListModel(strings,QObject parent = None)
其中strings为要展示的字符串列表数据。
2.2.2、初始化model中的数据
如果创建的model中无数据,可以通过几种方法初始化model中的数据:
- 使用setStringList(str)方法完成初始化,示例代码:
self.model1.setStringList(["item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"])
-
使用insertRows()、index()、setData()方法组合实现
insertRows是在model中插入空的数据记录,只是占据了数据位置,但没有实际的数据,需要通过setData来生成实际存储的数据。这种组合方法没有多大实际价值,具体方法的参数及含义在此不进行详细介绍。 -
使用视图的setModel(model)方法将model和view建立连接
2.2.3、示例代码及运行截图
本示例代码使用先创建对象再使用setStringList方法初始化数据:
def initStringListModel(self):
strList = ["item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"]
self.model = QStringListModel()
self.model.setStringList(strList )
self.listView.setModel(self.model)
运行截图:
三、QListView/QFileSystemModel
3.1、概述
QFileSystemModel提供了将本地文件系统中指定目录文件结构树形文件列表的进行存储的model类,它提供对本地文件系统的访问,提供重命名和删除文件和目录以及创建新目录的功能。在最简单的情况下,它可以作为浏览器或过滤器的一部分与适当的显示部件一起使用。
虽然QListView是单层次的视图,QFileSystemModel是树形层次的model,但还是可以在QListView中使用类似QFileSystemModel这种树状层次数据Model。只是视图展示时只会展示最顶层的数据,因此实际意义不大。
3.2、使用QFileSystemModel作为QListView的Model
使用QFileSystemModel来作为QListView的model非常简单,只有三步就可以实现:
-
创建QFileSystemModel对象
-
使用setRootPath设置QFileSystemModel对应文件的目录路径
-
使用视图的setModel(model)方法将model和view建立连接
3.3、示例代码
def initDirModel(self):
self.model = QtWidgets.QFileSystemModel()
self.model.setRootPath(r"c: emp")#监视目录异动
self.listView.setModel(self.model)
self.listView.setRootIndex(self.model.index(r"c: emp"))()))#切换显示目录
运行截图:
四、QListView/QStandardItemModel
4.1、概述
QStandardItemModel是Model/View架构中用于存储自定义数据的通用Model,它提供了一种经典的基于项的方法来处理模型,模型中的项类型必须是QStandardItem类或其派生子类。
QStandardItemModel实现QAbstractItemModel定义的接口,这意味着该模型可以用于在任何支持该接口的视图(例如QListView、QTableView和QTreeView,以及自己的自定义视图)中提供数据。为了实现性能和灵活性,需要对从QAbstractItemModel模型派生子类,以提供对不同类型的数据存储的支持,例如,QDirModel为底层文件系统提供一个模型接口。
4.2、使用QStandardItemModel作为QListView的Model
由于QStandardItemModel是一个通用的Model,使用它作为视图的Model实现起来比类似QFileSystemModel等便利化专用化的Model要稍微复杂,其复杂主要是数据初始化方面。具体实现步骤如下:
-
创建Model对象
可以使用QStandardItemModel(parent: QObject = None)、QStandardItemModel(int rowCount, int columnCount, parent: QObject = None)来创建Model对象。 -
初始化数据
初始化数据时,需要每个数据创建一个QStandardItem或其派生类的对象,并将其加入到Model中去。QStandardItem类有四个构造方法QStandardItem()、QStandardItem(str text)、QStandardItem(QIcon icon, str text)、QStandardItem(int rows, int columns = 1),分别用于创建单个空项、一个带数据的项、一个带图标和数据的项、多个空项,对于空项还需要使用setText(QVariant value, int role = Qt.UserRole + 1)等方法设置项存储的数据。 -
使用视图的setModel(model)方法将model和view建立连接
4.3、 一个完整的初始化方法代码及运行截图
def initStandItemModel(self):
self.model = QStandardItemModel()
strList = ["item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"]
row = 0
for itemStr in strList:
item = StandardItem(itemStr)
self.model.setItem(row, 0, item)
row += 1
self.listView.setModel(self.model)
运行截图:
五、QListView与多列Model及使用QListView的modelColumn属性
5.1、概述
QListView的modelColumn属性用于控制视图中展现model中哪一列数据,缺省值为0,即展现第一列数据。
可以通过modelColumn()、setModelColumn(int column)来访问和设置该属性。但Qt Designer中该属性值只能为0,无法设置为非0,这是因为QListView只显示一列数据,一般情况下如果使用的Model没有多列数据的话,是无需设置modelColumn属性,但并不是不能使用多列数据的Model。如上面第三部分使用QFileSystemModel与QListView配合使用。
5.2、使用多列模式初始化
下面是一个使用QStandardItemModel创建的一个6行5列的Model与QListView配合使用的初始化代码:
def initMultiColumnModel(self):
self.model = QStandardItemModel()
for row in range(6):
for col in range(5):
item = StandardItem("row: {row},col: {col}".format(row=row + 1, col=col + 1))
self.listView.setModel(self.model)
如使用QFileSystemModel来测试,发现可以通过setModelColumn来调整显示的数据内容,然后又改成了QStandardItemModel,使用model的setItem方法来设置多列数据,也可以使用setModelColumn来调整显示数据。
5.3、多列模式动态调整显示数据列
多列模式的Model初始化后显示的是第一列数据,如果要调整显示其他列的数据,可以通过setModelColumn来调整显示列。
六、支持列表中展示图标的两种方法
在视图中的项不但可以展示文字,也可以展示图标和复选框,同时可以指定项是否可以拖拽、选择、编辑。有两种方法支持在项中展示图标。
6.1、使用QStandardItem(QIcon icon, str text)创建项
下面的代码支持将指定目录的图象文件的文件名和图象在视图中展示:
def initIconModel(self):
self.model = QStandardItemModel()
ICon1 = QStandardItem(QIcon(r"F:学习python资源图像文件add.png"),'add.png')
ICon2 = QStandardItem(QIcon(r"F:学习python资源图像文件application_windows_add.png"), 'application_windows_add.png')
ICon3 = QStandardItem(QIcon(r"F:学习python资源图像文件save.png"), 'save.png')
ICon4 = QStandardItem(QIcon(r"F:学习python资源图像文件search.png"), 'search.png')
ICon5 = QStandardItem(QIcon(r"F:学习python资源图像文件stop.gif"), 'stop.gif')
self.model.appendRow(ICon1)
self.model.appendRow(ICon2)
self.model.appendRow(ICon3)
self.model.appendRow(ICon4)
self.model.appendRow(ICon5)
self.listView.setModel(self.model)
运行后的界面初始化截图如下:
6.2、使用QStandardItem()创建空项后通过setData指定图标文件为Qt.DecorationRole角色的数据
使用项的setData( QtCore.QVariant(icon), Qt.DecorationRole)方法,对应数据角色使用 Qt.DecorationRole。示例代码:
def initIconModel(self):
self.model = QStandardItemModel()
ICon1 = QStandardItem('add.png')
ICon1.setData(QtCore.QVariant(QIcon(r"F:学习python资源图像文件add.png")),Qt.DecorationRole)
ICon2 = QStandardItem('save.png')
ICon2.setData(QtCore.QVariant(QIcon(r"F:学习python资源图像文件save.png") ),Qt.DecorationRole)
self.model.appendRow(ICon1)
self.model.appendRow(ICon2)
self.listView.setModel(self.model)
运行截图:
其实还有个类似的方法,就是使用model的setData( QModelIndex,QtCore.QVariant(icon), Qt.DecorationRole)方法,当选择操作时要更改图标文件可以使用这种方法。只要在方法中获取到modelIndex就可以调用该方法。
七、支持获取变更数据的方法
在QListView视图中数据如果发生变化,可以通过QStandardItemModel的信号itemChanged连接一个自定义槽函数来获取变动的数据。
1、定义一个槽函数itemChanged
def itemChanged(self,item):
print(f"itemChanged,row={item.row()},column={item.column()}")
2、在构造方法中建立信号和槽的连接
self.model.itemChanged[QStandardItem ].connect(self.itemChanged)
这样只要触发了项的编辑就会发出该信号从而知道变动的数据项。
八、小结
本节通过案例详细介绍了QListView/Model编程的几个要点,包括QListView与不同model的配合步骤、多列Model中数据展示列的控制、给展示数据加上图标、获取变更数据项的方法等内容。
后记
另外老猿关于PyQt的付费专栏《使用PyQt开发图形界面Python应用》只需要9.9元,该部分与第十五章的内容基本对应,但同样内容在付费专栏上总体来说更详细、案例更多。本节内容在付费专栏的《第十八章、QListView/Model开发》。如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。
最后感谢各位支持,你们的支持是我持续学习和更新的动力!