PyQt5从入门到实践系列-19-玩转GUI中的数据库-01

2 篇文章 1 订阅

在这里插入图片描述
通过Python语言,我们可以很方便地对各类数据库进行查询等操作,比如轻量型的SQLite3数据库、MySQL数据库等。而要在GUI界面上显示和操作数据库中的数据,就需要借助PyQt5中的QtSQL模块,其提供了数据库连接、数据表和SQL操作的各种类。QT中的各种SQL相关类如下图所示。
在这里插入图片描述

从数据库中获取的数据可以直接用QSqlTableModel、QSqlQueryModel等模型类表示,可以与QTableView等类组成Model/View结构,便于高效实现数据和GUI界面的交互操作。

本期,我们主要针对,Qt SQL中的QSqlTableModel,QDataWidgetMapper,QSqlDatabase三个类并基于一个简单的小项目进行展开介绍。我们打算做这样的一个GUI界面,其主要目的包括:打开db文件或者连接MySQL数据库【下期介绍】,并将数据记录展示在一个QTableView中,同时通过QDataWidgetMapper类与QSqlTableModel数据模型建立连接,然后将数据表的某个字段与界面上其它控件建立映射,那么界面组件就可以自动显示这个字段的数据内容。该GUI界面实现插入、删除、新增、追加、根据表头执行排序等功能,同时还能实现将数据记录另存为cvs格式文件并保存到本地。ui界面设计相关不再赘述,有兴趣请看往期介绍。

在这里插入图片描述
在这里插入图片描述

1、加载sqlite3数据库db文件

@pyqtSlot()
def on_openFile_triggered(self):
    dbFilename, filter = QFileDialog.getOpenFileName(self, "选择数据库文件", "",
                                                      "SQL Lite数据库(*.db *.db3)")
    if (dbFilename == ''):
        return
    # QSqlDatabase打开数据库,用于建立与数据库之间的连接,加载所对应的数据库驱动
    # 此处为sqlite3数据库,驱动为QSQLITE,mysql数据库对应QMYSQL
    self.DB = QSqlDatabase.addDatabase("QSQLITE")
    self.DB.setDatabaseName(dbFilename)
    # self.DB.setHostName("localhost") 设置主机名
    # self.DB.setUserName("root") 设置用户名
    # self.DB.setPassword("123456") 设置登录密码
    # self.DB.setPort(3306) 设置端口
    if self.DB.open():
        self.open_table()
    else:
        QMessageBox.warning(self, "错误", "打开数据库失败")插入代码片

2、Model/View结构数据显示

GUI中操作数据库的目的在于将数据表记录在界面上进行显示和编辑,在Pyqt5中一般采用Model/View的结构进行记录显示。QtableView就是PyQT中常用的数据内容显示View组件,而常见的数据库操作的数据模型类有QSqlQueryModel、QSqlTableModel等。本期我们重点介绍QSqlTableModel。*

def open_table(self):
    #建立QSqlTableModel模型,参数为数据表名称,获取数据表的全部、可编辑的记录
    self.tableModel = QSqlTableModel(self, self.DB) # 数据模型,参数为数据库名称,通过QFileDialog打开
    self.tableModel.setTable("score") # 设置数据表名称
    self.tableModel.setEditStrategy(QSqlTableModel.OnManualSubmit) # 数据保存方式,OnManualSubmit , OnRowChange
    if (self.tableModel.select() == False):
        QMessageBox.critical(self, "错误信息",
                             "打开数据表错误,错误信息\n" + self.tableModel.lastError().text())
        return
    self.getFieldNames() #获取字段名称字典的函数
    self.tableModel.setHeaderData(self.fldNum["ID"], Qt.Horizontal, "学号")
    self.tableModel.setHeaderData(self.fldNum["NAME"], Qt.Horizontal, "姓名")
    self.tableModel.setHeaderData(self.fldNum["SEX"], Qt.Horizontal, "性别")
    self.tableModel.setHeaderData(self.fldNum["AGE"], Qt.Horizontal, "年龄")
    self.tableModel.setHeaderData(self.fldNum["YUWEN"], Qt.Horizontal, "语文")
    self.tableModel.setHeaderData(self.fldNum["SHUXUE"], Qt.Horizontal, "数学")
    self.tableModel.setHeaderData(self.fldNum["YINGYU"], Qt.Horizontal, "英语")
    self.tableModel.setHeaderData(self.fldNum["WULI"], Qt.Horizontal, "物理")
    self.tableModel.setHeaderData(self.fldNum["HUAXUE"], Qt.Horizontal, "化学") # 这两个字段不在tableView中显示
    self.tableModel.setHeaderData(self.fldNum["SHENGWU"], Qt.Horizontal, "生物")

    ##创建界面组件与数据模型的字段之间的数据映射
    self.mapper = QDataWidgetMapper()
    self.mapper.setModel(self.tableModel)
    self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

    ##界面组件与tabModel的具体字段之间的联系
    self.mapper.addMapping(self.ui.lineEdit_2, self.fldNum["ID"])
    self.mapper.addMapping(self.ui.lineEdit_3, self.fldNum["NAME"])
    self.mapper.addMapping(self.ui.comboBox_2, self.fldNum["SEX"])
    self.mapper.addMapping(self.ui.lineEdit_5, self.fldNum["AGE"])
    self.mapper.addMapping(self.ui.lineEdit_6, self.fldNum["YUWEN"])
    self.mapper.addMapping(self.ui.lineEdit_7, self.fldNum["SHUXUE"])
    self.mapper.addMapping(self.ui.lineEdit_8, self.fldNum["YINGYU"])
    self.mapper.addMapping(self.ui.lineEdit_4, self.fldNum["WULI"])
    self.mapper.addMapping(self.ui.lineEdit_9, self.fldNum["HUAXUE"])
    self.mapper.addMapping(self.ui.lineEdit_10, self.fldNum["SHENGWU"])
    self.mapper.toFirst() # 移动到首记录
    self.selectModel = QItemSelectionModel(self.tableModel) # 选择模型
    self.selectModel.currentChanged.connect(self.do_currentChanged) # 当前项变化时触发
    self.selectModel.currentRowChanged.connect(self.do_currentRowChanged) # 选择行变化时
    
    #将QSqlTableModel模型设置为界面上的QTableView组件的Model/View数据模型就可以显示和编辑数据
    self.ui.tableView.setModel(self.tableModel) # 设置数据模型
    self.ui.tableView.setSelectionModel(self.selectModel) # 设置选择模型

    # 表格宽度的自适应调整
    self.ui.tableView.horizontalHeader().setStretchLastSection(True)
    self.ui.tableView.horizontalHeader().setSectionsClickable(True)
  
    #设置tableView背景前景
    self.ui.tableView.setAlternatingRowColors(True)
    self.ui.tableView.setStyleSheet("alternate-background-color: rgb(110, 110, 110)"
                                    "; background-color: rgb(55, 180, 210);")
  
    #设置表头排序功能及表头样式
    self.ui.tableView.setSortingEnabled(True)
    self.ui.tableView.horizontalHeader().setStyleSheet(
        "::section{background-color: pink; color: blue; font-weight: bold}")
    self.ui.tableView.verticalHeader().hide()

3、数据操作

此功能界面实现数据插入、追加、保存、删除、排序等操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@pyqtSlot()
def on_Save_triggered(self):
    res = self.tableModel.submitAll()
    if (res == False):
        QMessageBox.information(self, "消息",
                                "数据保存错误,错误信息\n" + self.tableModel.lastError().text())
    else:
        self.ui.Save.setEnabled(False)

@pyqtSlot() ##取消修改
def on_Cancel_triggered(self):
     self.tableModel.revertAll()

@pyqtSlot() ##添加记录
def on_Add_triggered(self):
     self.tableModel.insertRow(self.tableModel.rowCount(), QModelIndex()) # 在末尾添加一个记录
     curIndex = self.tableModel.index(self.tableModel.rowCount() - 1, 1) # 创建最后一行的ModelIndex
     self.selModel.clearSelection()
     self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) # 设置刚插入的行为当前选择行
     currow = curIndex.row() # 获得当前行
     self.tableModel.setData(self.tableModel.index(currow, self.fldNum["ID"]),2 + self.tableModel.rowCount()) # 自动生成编号
     self.tableModel.setData(self.tableModel.index(currow, self.fldNum["YINGYU"]), 100)

@pyqtSlot()
def on_insert_triggered(self):
    curIndex = self.ui.tableView.currentIndex() # QModelIndex
    self.tableModel.insertRow(curIndex.row(), QModelIndex())
    self.selModel.clearSelection() # 清除已有选择
    self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

@pyqtSlot()
def on_delete_2_triggered(self):
    curIndex = self.selModel.currentIndex() # 获取当前选择单元格的模型索引
    self.tabModel.removeRow(curIndex.row()) # 删除当前行

4、数据导出为csv-将数据表文件导出为csv结构化数据

@pyqtSlot()
def on_saveAs_triggered(self):
    options = QFileDialog.Options()
    file_name, _ = QFileDialog.getSaveFileName(self, "保存为CSV文件", "", "CSV文件 (*.csv)", options=options)
    if file_name:
        with open(file_name, 'w', newline='') as csvfile:
            writer = csv.writer(csvfile)
            for row in range(self.tabModel.rowCount()):
                row_data = [self.tabModel.data(self.tabModel.index(row, col)) for col in range(self.tabModel.columnCount())]
                writer.writerow(row_data)

在这里插入图片描述
还有一个重要的功能尚未实现,即数据分页显示的问题,这个我们下期详解。
在这里插入图片描述

5、总结

本小节,通过一个下案例详细介绍了PyQt5里面的数据库、表显示及操作。GUI中的Mysql以及更多的内容,我们后期详解。敬请关注。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值