最新项目需要在PyQt中使用表格,列表等样式.一开始我的写法很简单,在Qt-designer中拖了QListWidget与QTableWidget.
向tableWdiget动态添加一行采用如下代码
def _insert_to_table(self, tableWidget):
'''将数据插入到表格中,self.table_data保存了一行所有数据'''
tableWidget.insertRow(tableWidget.rowCount())
for column in range(tableWidget.columnCount()):
# print(self.table_data[column])
item = QTableWidgetItem(str(self.table_data[column]))
tableWidget.setItem(tableWidget.rowCount() - 1, column, item)
向listWidget动态添加一行采用如下代码
self.listWidget.addItem(name)
但这样很恶心,动态扩展性很差.网上对PyQt中QAbstractTableModel/QStringListModel介绍的很少,下面介绍一种符合Model/view设计模式的方法.当然仅仅贴出一段例子,具体细节要是要去参考官方文档.
dialog.py
# @Author : 张帆
# @Site :
# @File : teamleadersdialog.py
# @Software: PyCharm
import sys
from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import QDialog, QListView, QAbstractItemView, QDialogButtonBox, QVBoxLayout, QTableView, \
QApplication
from learnMVC.currencymodel import CurrencyModel
class TeamLeadersDialog(QDialog):
def __init__(self, leaders):
super(TeamLeadersDialog, self).__init__()
self.model = QStringListModel(self)
self.model.setStringList(leaders)
self.listView = QListView()
self.listView.setModel(self.model)
self.listView.setEditTriggers(QAbstractItemView.AnyKeyPressed | QAbstractItemView.DoubleClicked)
self.buttonBox = QDialogButtonBox()
self.insertButton = self.buttonBox.addButton("Insert", QDialogButtonBox.ActionRole)
self.deleteButton = self.buttonBox.addButton("Delete", QDialogButtonBox.ActionRole)
self.buttonBox.addButton(QDialogButtonBox.Ok)
self.buttonBox.addButton(QDialogButtonBox.Cancel)
self.insertButton.clicked.connect(self.insert)
self.deleteButton.clicked.connect(self.del_)
self.currencyMap = {
"header": ["姓名", "性别", "年龄"],
"data": [["张帆", "男", 24], ["张帆", "男", 24], ["张帆", "男", 24], ["张帆", "男", 24], ["张帆", "男", 24],
["张帆", "男", 24]]
}
self.currencyModel = CurrencyModel(self.currencyMap.get('data'),self.currencyMap.get('header'))
self.tableView = QTableView()
self.tableView.setModel(self.currencyModel)
self.tableView.setAlternatingRowColors(True)
self.tableView.setWindowTitle("Currencies")
self.tableView.show()
self.mainLayout = QVBoxLayout()
self.mainLayout.addWidget(self.listView)
self.mainLayout.addWidget(self.buttonBox)
self.mainLayout.addWidget(self.tableView)
self.setLayout(self.mainLayout)
self.setWindowTitle("Team leaders")
self.count = 0
def leaders(self):
return self.model.stringList()
def insert(self):
row = self.model.rowCount()
print(row)
self.model.insertRow(row)
index = self.model.index(row)
self.model.setData(index,"123")
currencyMap = {
"header": ["姓名", "性别", "年龄"],
"data": [["张帆", "男", 242], ["张帆", "男", 24], ["张帆", "男", 24], ["张帆", "男", 24], ["张帆", "男", 24],
["张帆", "男", 24],['sdaf','asdf','asdf']]
}
x = self.tableView.currentIndex()
self.currencyModel.append_data(['zhangfan','nf',str(self.count)])
self.count+=1
print(self.currencyModel.data)
def del_(self):
self.model.removeRows(self.listView.currentIndex().row(), 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
leaders = ['1','2','3','4','5','6','6']
teamLeadersDialog = TeamLeadersDialog(leaders)
teamLeadersDialog.show()
app.exec_()
currencymodel.py
# -*- coding: utf-8 -*-
# @Time : 18-12-1 下午3:26
# @Author : 张帆
# @Site :
# @File : currencymodel.py
# @Software: PyCharm
from PyQt5.QtCore import QAbstractTableModel, QVariant, Qt
class CurrencyModel(QAbstractTableModel):
def __init__(self,data:list,header):
super(CurrencyModel, self).__init__()
self.data = data
self.header = header
def append_data(self,x):
self.data.append(x)
self.layoutChanged.emit()
def remove_row(self,row):
self.data.pop(row)
self.layoutChanged.emit()
def rowCount(self, parent=None, *args, **kwargs):
return len(self.data)
def columnCount(self, parent=None, *args, **kwargs):
if len(self.data) > 0:
return len(self.data[0])
return 0
def get_data(self):
return self
# 返回一个项的任意角色的值,这个项被指定为QModelIndex
def data(self, QModelIndex, role=None):
if not QModelIndex.isValid():
print("行或者列有问题")
return QVariant()
# if role == Qt.TextAlignmentRole:
# return int(Qt.AlignRight | Qt.AlignVCenter)
# elif role == Qt.DisplayRole:
# row = QModelIndex.row()
# column = QModelIndex.column()
# return self.currencyMap.get('data')[row][column]
# # print("查数据")
# row = QModelIndex.row()
# # print('role:',role)
# if role is None:
# return self.currencyMap.get('data')[row]
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.data[QModelIndex.row()][QModelIndex.column()])
def headerData(self, p_int, Qt_Orientation, role=None):
# if role != Qt.DisplayRole:
# return QVariant()
# else:
# if Qt_Orientation == Qt.Horizontal:
# if len(self.currencyMap.get('header')) > p_int:
# return self.currencyMap.get('header')[p_int]
if Qt_Orientation == Qt.Horizontal and role == Qt.DisplayRole:
return QVariant(self.header[p_int])
return QVariant
这种方法有什么好的呢?我认为这样可以实现动态绑定,我们通过修改列表中的数据,就可以该表视图中的数据.优势是不言而喻的.QStringListModel就不在解释了,挺简单的.下面对使用到currencymodel.py 简单的解释以下,我自己也不太明白,如有问题,请指出.
1.首先该类继承了QAbstractTableModel,就必须要实现rowCount(),columnCount(),data(),headerData()
2.初始化:
1.指定表格数据结构,我设计的结构为 [['xxx','xxx','xxx'],['ttt','ttt','ttt'],...,]
2.指定表头数据结构,我设计的结构为['xxx','xxx','xxx']
2.rowCount() 要返回该表格的行数
3.columnCount() 返回该表格的列数
4.data() 此方法我也不太了解,但调试时发现,他会经常逐表格调用,QModelIndex的值会根据行数列数的值,遍历每一个单元格
所以此处根据QModelIndex返回每一个单元格的值
5.headerData 与4相似,会根据列数自动调用
6.append_data 如果我们要动态的增加一行,只需要向self.data列表增加一行,之后调用self.layoutChanged.emit()即可
7.remove_data 同上,如果要动态删除一行,只需要将self.data指定行删除,之后调用self.layoutChanged.emit()即可.
至此,我们就可以实现数据与视图绑定,进一步实现set_data 应该可以实现双向绑定(vue....)
网上关于pyqt的资料真的很少,这点东西,都是花了1天的时间,看了不少C++代码才写出来的,感觉qt相对于前端氛围还是太差了,是不是要被淘汰呢...总而言之,希望这些对大家有所帮助.