pyqt QTableView
PyQt5高级界面控件之QTableWidget(四) - jia666666的博客 - CSDN博客
QTableView 实现Excel表格编辑功能
PyQt5使用记录之二 —— QTableView实现数据的显示、编辑、删除与添加 - cloveses的专栏 - CSDN博客
PyQt5高级界面控件之QTableView(一) - jia666666的博客 - CSDN博客
QTableWidget与QTableView的区别?
QTableWidget继承自QTableView。QSqlTableModel能与QTableView绑定,但不能于QTableWidget绑定
前言
在通常情况下,一个应用需要和一批数据进行交互,然后以表格的形式输出这些信息,这时就需要用到QTableView类了,在QTableView中可以使用自定义的数据模型来显示内容,通过setModel来绑定数据源
QTableWidget继承自QTableView,主要区别是QTableView可以使用自定义的数据模型来显示内容(先通setModel来绑定数据源),而QTableWidget自能使用标准的数据模型,并且其单元格数据是通过QTableWidgetItem对象实现的,通常QTableWidget就能够满足我们的要求
QTableView可用的模式
QTableView控件可以绑定一个模型数据用来更新控件上的内容
名称 | 含义 |
---|---|
QStringListModel | 储存一组字符串 |
QstandardItemModel | 存储任意层次结构的数据 |
QDirModel | 对文件系统进行封装 |
QSqlQueryModel | 对SQL的查询结果集进行封装 |
QSqlTableModel | 对SQL中的表格进行封装 |
QSqlRelationalTableModel | 对带有foreign key的SQL表格进行封装 |
QSortFilterProxyModel | 对模型中的数据进行排序或过滤 |
实例:QTableView的使用
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class Table(QWidget):
def __init__(self,parent=None):
super(Table, self).__init__(parent)
#设置标题与初始大小
self.setWindowTitle('QTableView表格视图的例子')
self.resize(500,300)
#设置数据层次结构,4行4列
self.model=QStandardItemModel(4,4)
#设置水平方向四个头标签文本内容
self.model.setHorizontalHeaderLabels(['标题1','标题2','标题3','标题4'])
# #Todo 优化2 添加数据
# self.model.appendRow([
# QStandardItem('row %s,column %s' % (11,11)),
# QStandardItem('row %s,column %s' % (11,11)),
# QStandardItem('row %s,column %s' % (11,11)),
# QStandardItem('row %s,column %s' % (11,11)),
# ])
for row in range(4):
for column in range(4):
item=QStandardItem('row %s,column %s'%(row,column))
#设置每个位置的文本值
self.model.setItem(row,column,item)
#实例化表格视图,设置模型为自定义的模型
self.tableView=QTableView()
self.tableView.setModel(self.model)
# #todo 优化1 表格填满窗口
# #水平方向标签拓展剩下的窗口部分,填满表格
# self.tableView.horizontalHeader().setStretchLastSection(True)
# #水平方向,表格大小拓展到适当的尺寸
# self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
#
# #TODO 优化3 删除当前选中的数据
# indexs=self.tableView.selectionModel().selection().indexes()
# print(indexs)
# if len(indexs)>0:
# index=indexs[0]
# self.model.removeRows(index.row(),1)
#设置布局
layout=QVBoxLayout()
layout.addWidget(self.tableView)
self.setLayout(layout)
if __name__ == '__main__':
app=QApplication(sys.argv)
table=Table()
table.show()
sys.exit(app.exec_())
运行程序,显示效果如图
从图中可以看出,表格并没有填满窗口,每列都可以自由拉伸,但是可能会出现滚动条
优化1:需要表格填充满窗口,可以添加一下代码
#水平方向标签拓展剩下的窗口部分,填满表格
self.tableView.horizontalHeader().setStretchLastSection(True)
#水平方向,表格大小拓展到适当的尺寸
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
效果如下
优化2:添加数据
#Todo 优化2 添加数据
self.model.appendRow([
QStandardItem('row %s,column %s' % (11,11)),
QStandardItem('row %s,column %s' % (11,11)),
QStandardItem('row %s,column %s' % (11,11)),
QStandardItem('row %s,column %s' % (11,11)),
])
效果如图
优化3:删除当前选中的数据
indexs=self.tableView.selectionModel().selection().indexes()
print(indexs)
if len(indexs)>0:
index=indexs[0]
self.model.removeRows(index.row(),1)
相关文件及下载地址
https://download.csdn.net/download/jia666666/10609488
数据的显示、编辑、删除与添加也是GUI编程的常见功能,作为初用者,使用笨拙的方式基本实现的功能。运用QTableView和QStandardItemModel相结合的方式实现数据的显示与增、删、改。基本代码如下,详见注释:
.....
self.player_tabview = QTableView() # 建立QTableView类实例
self.player_model = QStandardItemModel() # 建立数据模型实例
self.player_model.setHorizontalHeaderLabels(head_lst) # 设置列标题
if datas: # 向模型添加数据
r,c = len(datas),len(datas[0])
for r,rdata in enumerate(datas):
for c,cell in enumerate(rdata):
it = QStandardItem(str(cell))
# it.setEditable(False) # 设置单元不可编辑
self.player_model.setItem(r,c,it)
self.player_tabview.setModel(self.player_model) # 添加模型到QTableView实例中
self.player_model.itemChanged.connect(functools.partial(self.edit_cell,obj,keys)) # 当某单元格被编辑后,会触发该信号,并调用edit_cell方法
del_btn = QPushButton('删除')
del_btn.clicked.connect(self.del_row) # 删除行的按钮信号与槽的连接
add_btn = QPushButton('添加分组')
add_btn.clicked.connect(self.add_group) # 添加行的按钮信号与槽的连接
def del_row(self):
reply = QMessageBox.question(self, '确认', '确定删除数据?',QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
r = self.player_tabview.currentIndex().row()
item = self.player_model.index(r,0)
del_rowdb(Team,int(item.data())) # 调用删除数据的方法
self.player_model.removeRow(r)
def edit_cell(self,obj,keys,abc): # 编辑数据调用的方法
# abc QStandardItem对象
print(obj,keys,abc,abc.whatsThis())
r = self.player_tabview.currentIndex().row() # 获取行号
c = self.player_tabview.currentIndex().column() # 获取列序
curr_data = self.player_tabview.currentIndex().data()
item = self.player_model.index(r,0)
param = dict()
param[keys[c]] = curr_data
save_cell(obj,int(item.data()),param)
def addgroup(self): # 添加数据方法
v = MyDialog()
if v.exec():
name,game = v.get_data() # 通过自定义对话框获取要建立行的数据
if name and game:
info = add_groupdb(name,int(game))
if info:
QMessageBox.warning(self,'错误',info,QMessageBox.Ok)
else:
QMessageBox.information(self,'完成','成功建立!',QMessageBox.Ok)
self.edit_group()
后来,通过查阅资料,了解了PyQt5的Model/View/Delegate的设计模式,即Model持有数据,下与数据源交互(数据的查询、修改与添加),上与View交互,主要为View提供要显示的数据。View提供数据的显示和与用户交互。Delegate可以实现定制数据显示的方式和编辑方式,在实际使用时,Delegate可以不用自定义,而使用默认的实现即可。实现简单的功能,只通过继承PyQt5.QtCore.QAbstractTableModel能更方便的实现数据的CRUD,但是需要了解必须实现的接口方法及其功能。以下是通过继承PyQt5.QtCore.QAbstractTableModel自定义自定义一个Model的实例代码。
from PyQt5.QtCore import QAbstractTableModel,QModelIndex,QVariant,Qt
from models.mydb import TObj,db_session,select
ID,NAME,AGE,TEL = range(4)
HEADERS = ('id','姓名','年龄','电话')
CONVERTS_FUNS = (None,None,int,None)
class TObjModel(QAbstractTableModel):
def __init__(self,headers=HEADERS):
super().__init__()
self.datas = [] # 用来持有为View提供的数据,此类中用列表中嵌套列表来实现
self.headers = headers
self.load() # 初始化时,自动载入数据
def load(self):
# 载入数据函数,可以从任何数据源载入
self.beginResetModel()
with db_session: # 这里使用Pony这个ORM来完成数据库的操作
tobjs = select(t for t in TObj)
for tobj in tobjs:
self.datas.append([tobj.id,tobj.name,tobj.age,tobj.tel])
print(self.datas)
self.endResetModel()
def data(self,index,role=Qt.DisplayRole):
# 供视图调用,以获取用以显示的数据
if (not index.isValid() or not (0 <= index.row() < len(self.datas))): # 无效的数据请求
return None
row,col = index.row(),index.column()
data = self.datas[row]
if role == Qt.DisplayRole:
item = data[col]
if col == AGE: # 还可以实现数据的转换显示或显示处理后的数据
item = int(item)
return item
return None
def rowCount(self,index=QModelIndex()): # 必须实现的接口方法(返回数据行数)
return len(self.datas)
def columnCount(self,index=QModelIndex()): # 必须实现的接口方法(返回数据列数)
return len(self.headers)
def headerData(self,section,orientation,role=Qt.DisplayRole):
# 实现标题行的定义
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
return self.headers[section]
return int(section + 1)
# 以下为编辑功能所必须实现的方法
def setData(self,index,value,role=Qt.EditRole):
# 编辑后更新模型中的数据 View中编辑后,View会调用这个方法修改Model中的数据
if index.isValid() and 0 <= index.row() < len(self.datas) and value:
col = index.column()
print(col)
if 0 < col < len(self.headers):
self.beginResetModel()
if CONVERTS_FUNS[col]: # 必要的时候执行数据类型的转换
self.datas[index.row()][col] = CONVERTS_FUNS[col](value)
else:
self.datas[index.row()][col] = value
self.dirty = True
self.endResetModel()
return True
return False
def flags(self, index): # 必须实现的接口方法,不实现,则View中数据不可编辑
if not index.isValid():
return Qt.ItemIsEnabled
return Qt.ItemFlags(
QAbstractTableModel.flags(self, index)|
Qt.ItemIsEditable | Qt.ItemIsSelectable)
def insertRows(self,position,rows=1,index=QModelIndex()):
# position 插入位置;rows 插入行数
self.beginInsertRows(QModelIndex(),position,position + rows -1)
pass # 对self.datas进行操作
self.endInsertRows()
self.dirty = True
return True
def removeRows(self,position,rows=1,index=QModelIndex):
# position 删除位置;rows 删除行数
self.beginRemoveRows(QModelIndex(),position,position + rows -1)
pass # 对self.datas进行操作
self.endRemoveRows()
self.dirty = True
return True
# 可单独定义保存数据的方法(遍历datas进行保存),供用户退出时或选择保存时,保存数据
# 也可以在用户编辑时立即保存,即在setData方法中保存
使用这个类的方法很简单,只要实例化后,并将其设置为QTableView的Model即可,也可在适当的时候,调用其load()方法,重新载入数据。代码就更简单了:
self.player_tabview = QTableView()
self.player_model = TObjModel()
self.player_tabview.setModel(self.player_model)
————————————————
版权声明:本文为CSDN博主「cloveses」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cloveses/article/details/80943496