PqQt实现对数据库的添加,删除,修改(完整过程演示

简介: PqQt实现对数据库的添加,删除,修改(完整过程演示

在PyQt中设置的如下的窗口:



其中的图标是通过新建Resource File加入的



images里面的图片可以在这里面取:


链接:https://pan.baidu.com/s/1gOgBpW7s-ZWn_5aRoaYLkQ

提取码:jyjy


我们把这个文件取名为res.qrc



资源文件的使用可以看这里:http://t.csdn.cn/ba4X4


因为结构有些复杂,对于窗口的ui文件可以从这里自取


链接:https://pan.baidu.com/s/1NKFRtbxS_xE9eQq_bd_hnA

提取码:jyjy


1.建立如下数据库:



2.新建appMain文件


import sys
from PyQt6.QtWidgets import QApplication
from myMainWindow import QmyMainWindow
app=QApplication(sys.argv)#构造GUI应用程序
mainform=QmyMainWindow() #创建主窗体
mainform.show() #显示主窗体
sys.exit(app.exec())

3.新建myMainWindow文件


其中def on_actOpenDB_triggered是通过添加槽函数得来的



点击后选择trigger信号



其他按钮操作类似,这里不再一一演示:

import sys
from PyQt6.QtWidgets import (QApplication,QMainWindow, QMessageBox, 
                                            QAbstractItemView, QDataWidgetMapper)
from PyQt6.QtSql import QSqlDatabase, QSqlTableModel
from PyQt6.QtCore import pyqtSlot,Qt, QItemSelectionModel, QModelIndex
from Ui_MainWindow import Ui_MainWindow
from myDelegates import QmyComboBoxDelegate
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent) #调用父类构造函数,创建窗体
        self.ui=Ui_MainWindow() #创建UI对象
        self.ui.setupUi(self)  #构造UI界面
       
        self.setCentralWidget(self.ui.splitter) #将splitter放在窗体中间
       
        #限制选择时只能选择一行
        self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.
        SelectItems)
        self.ui.tableView.setSelectionMode(QAbstractItemView.SelectionMode.
        SingleSelection)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.verticalHeader().setDefaultSectionSize(22)
        self.ui.tableView.horizontalHeader().setDefaultSectionSize(100)
       
   
    @pyqtSlot()   
    def on_actOpenDB_triggered(self):
        self.DB=QSqlDatabase.addDatabase("QODBC")
        self.DB.setDatabaseName("Driver={sql Server};Server=localhost;Database=pyqt;Uid=pyqt;Pwd=xxx")
        if self.DB.open():#打开数据库
            self.__openTable()#打开数据表
        else:
            QMessageBox.warning(self, "错误", "打开数据失败")
           
#添加下拉框的数据
    def __getFieldNames(self):##获取所有字段名称
        emptyRec=self.tabModel.record()#获取空记录,只有字段名
        self.fldNum={}#字段名与序号的字典
        for i in range(emptyRec.count()):
            fieldName=emptyRec.fieldName(i)
            self.ui.comboFields.addItem(fieldName)
            self.fldNum.setdefault(fieldName)
            self.fldNum[fieldName]=i
       
    def __openTable(self):
        self.tabModel=QSqlTableModel(self, self.DB)#数据模型
        self.tabModel.setTable("employee")#设置数据表
        self.tabModel.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
        self.tabModel.setSort(self.tabModel.fieldIndex("EmoNo"), Qt.SortOrder.AscendingOrder)
        if(self.tabModel.select()==False):#查询数据失败
            QMessageBox.critical(self, "错误信息",
              "打开数据库错误,错误信息\n"+self.tabModel.lastError().text())
            return
           
        self.__getFieldNames()#获取字段名与序号
        #将表列名变为自定义的列名,可以显示表头
        self.tabModel.setHeaderData(0, Qt.Orientation.Horizontal, "工号")
        self.tabModel.setHeaderData(1, Qt.Orientation.Horizontal, "姓名")
        self.tabModel.setHeaderData(2, Qt.Orientation.Horizontal, "性别")
        self.tabModel.setHeaderData(3, Qt.Orientation.Horizontal, "出生日期")
        self.tabModel.setHeaderData(4, Qt.Orientation.Horizontal, "省份")
        self.tabModel.setHeaderData(5, Qt.Orientation.Horizontal, "部门")
        self.tabModel.setHeaderData(0, Qt.Orientation.Horizontal, "工资")
        self.tabModel.setHeaderData(0, Qt.Orientation.Horizontal, "备注") 
        self.ui.tableView.setModel(self.tabModel)#设置数据模型
        self.ui.tableView.resizeColumnsToContents()#重新调整列宽
       
#QDataWidgetMapper用于建立界面组件与数据模型的字段之间的数据映射。这样,我们选
#择一个tableView的行,才能在右边看到相关数据的信息。
#选择模型的作用是当用户在tableView上操作时,获取当前选择的行、列信息,并在选择的
#单元格变化时发射currentChanged信号,在当前行变化时发射currentRowChanqed()信号。
        self.mapper =QDataWidgetMapper()#创建界面组件与数据模型的字段之间的数据映射
        self.mapper.setModel(self.tabModel)#设置数据模型
        self.mapper.setSubmitPolicy(QDataWidgetMapper.SubmitPolicy.AutoSubmit)
       
        self.mapper.addMapping(self.ui.dbspinEmpNo, 0)
        self.mapper.addMapping(self.ui.dbEditName, 1)
        self.mapper.addMapping(self.ui.dbComboDep, 2)
        self.mapper.addMapping(self.ui.dbEditBirth, 3)
        self.mapper.addMapping(self.ui.comboBoxProvince, 4)
        self.mapper.addMapping(self.ui.dbComboDep, 5)
        self.mapper.addMapping(self.ui.dbSpinSalary, 6)
        self.mapper.addMapping(self.ui.dbEditMemo, 7)
        self.mapper.toFirst()#移动首记录
       
        self.selModel=QItemSelectionModel(self.tabModel)#选择模型
        self.ui.tableView.setSelectionModel(self.selModel)#设置选择模型
        self.selModel.currentChanged.connect(self.do_currentChanged)#当前项变化时触发
        self.selModel.currentRowChanged.connect(self.do_currentRowChanged)#选择行变化时
       
        strList=("男", "女")
        self.__delegateSex=QmyComboBoxDelegate()
        self.__delegateSex.setItems(strList, False)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Gender"], self.__delegateSex)
       
        strList=("浙江","蒙古","陆西","吉林","广东","新疆")
        self.__delegateProvince=QmyComboBoxDelegate()
        self.__delegateProvince.setItems(strList,True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Province"], self.__delegateProvince)
       
        strList=("销售部", "技术部","生产部","行政部")
        self.__delegateDepart=QmyComboBoxDelegate()
        self.__delegateDepart.setItems(strList, True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"], self.__delegateDepart)
       
#添加按钮状态
#数据表成功打开后,打开按钮失效,添加,插入,删除,涨工资相关按钮能按了
        self.ui.actOpenDB.setEnabled(False)
        self.ui.actRecAppend.setEnabled(True)
        self.ui.actRecInsert.setEnabled(True)
        self.ui.actRecDelete.setEnabled(True)
        self.ui.actScan.setEnabled(True)
   
#一开始,排序和数据过滤这两个groupBox里面的组件是不能选的。因为数据表没有打开,
#没法数据排序和数据过滤。
#数据表一旦打开,这两个GroupBox应该enabled
        self.ui.groupBoxSort.setEnabled(True)
        self.ui.groupBoxFilter.setEnabled(True)
       
    def do_currentChanged(self, current, previous):#更新actPost和actCancel状态
        self.ui.actSubmit.setEnabled(self.tabModel.isDirty())#有未保存修改时可用
        self.ui.actRevert.setEnabled(self.tabModel.isDirty())
       
    def do_currentRowChanged(self, current, previous):#行切换时状态控制
        self.mapper.setCurrentIndex(current.row())#更新数据映射的行号
#点降序。注意不改变EmpNo,直接点降序那个radio Button是没反应的,因为不会触发#currentindexChanged信号。
#只有在排序字段先点了降序,然后修改了ComboBox的索引,比如改到Salary,然后选回
#EmpNo,再次点击降序,才会变化。可以理解一下。只有ComboBox里面的索引改变了,
#才会触发槽函数。
    @pyqtSlot(int)##排序字段变化
    def on_comboFields_currentIndexChanged(self, index):
        if self.ui.radioBtnAscend.isChecked():
            self.tabModel.setSort(index, Qt.SortOrder.AscendingOrder)
        else:
            self.tabModel.setSort(index, Qt.SortOrder.DescendingOrder)
        self.tabModel.select()
   
    @pyqtSlot()    
    def on_radioBtnAscend_clicked(self):#升序
        self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.SortOrder.AscendingOrder)
        self.tabModel.select()
       
    @pyqtSlot()  
    def on_radioBtnDescend_clicked(self):#降序
        self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.SortOrder.DescendingOrder)
        self.tabModel.select()
       
    @pyqtSlot()  
    def on_radioBtnMan_clicked(self):#数据过滤,男
        self.tabModel.setFilter("Gender='男'")
       
    @pyqtSlot()
    def on_radioBtnWoman_clicked(self):#数据过滤,女
        self.tabModel.setFilter("Gender='女'")
       
    @pyqtSlot()#取消数据过滤
    def on_radioBtnBoth_clicked(self):
        self.tabModel.setFilter("")
       
    @pyqtSlot() ##添加记录
    def on_actRecAppend_triggered(self):
        self.tabModel.insertRow(self.tabModel.rowCount(), QModelIndex())#在末尾添加一个记录
        curIndex=self.tabModel.index(self.tabModel.rowCount()-1, 1)#创建最后一行的ModelIndex
        self.selModel.clearSelection()#清空选择项
        self.selModel.setCurrentIndex(curIndex,QItemSelectionModel.SelectionFlag.Select)#设置刚插入的行为当前选择行
        currow=curIndex.row()#获得当前行
        self.tabModel.setData(self.tabModel.index(currow,self.fldNum["EmpNo"]), 
                            2000+self.tabModel.rowCount())#自动生成编号
        self.tabModel.setData(self.tabModel.index(currow,self.fldNum["Gender"]),"男")
   
    @pyqtSlot()##插入记录
    def on_actRecInsert_triggered(self):
        curIndex=self.ui.tableView.currentIndex() #QModelIndex
        self.tabModel.insertRow(curIndex.row(), QModelIndex())
        self.selModel.clearSelection()#清楚已有选择
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.SelectionFlag.Select)
        currow=curIndex.row() #获得当前行
        self.tabModel.setData(self.tabModel.index(currow,self.fldNum["EmpNo"]), 
                            2000+self.tabModel.rowCount())#自动生成编号
        self.tabModel.setData(self.tabModel.index(currow,self.fldNum["Gender"]),"男")
       
    @pyqtSlot()
    def on_actRecDelete_triggered(self):##删除记录
        curIndex=self.selModel.currentIndex()
        self.tabModel.removeRow(curIndex.row())
       
    @pyqtSlot()##涨工资,遍历数据表所有数据
    def on_actScan_triggered(self):
        if(self.tabModel.rowCount()==0):
          return
        for i in range(self.tabModel.rowCount()):
            aRec=self.tabModel.record(i)#获取当前记录
            salary=aRec.value("Salary")
            salary=salary*1.1
            aRec.setValue("Salary", salary)
            self.tabModel.setRecord(i, aRec)
   
    @pyqtSlot()##edit策略需要手工submit
    def on_actSubmit_triggered(self):
        res=self.tabModel.submitAll()
        if(res==False):
            QMessageBox.information(self, "消息", "数据保存错误,错误信息\n"+self.tabModel.lastError().text())
        else:
            self.ui.actSubmit.setEnabled(False)
            self.ui.actRevert.setEnabled(False)
         
       
    @pyqtSlot()##取消修改
    def on_actRevert_triggered(self):
        self.tabModel.revertAll()
        self.ui.actSubmit.setEnabled(False)
        self.ui.actRevert.setEnabled(False)
       
           
        if(self.tabModel.submitAll()):
            QMessageBox.information(self, "消息", "涨工资计算完毕")
if __name__=="__main__": #用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyMainWindow() #创建窗体
    form.show()
    sys.exit(app.exec())


我们发现在数据库中将性别修改为不合理的X,可以成功保存



而右侧框,因为有下拉框限定,不会修改为X



怎么解决这个问题呢?


要对tableview里面数据的修改进行限制。

tableview默认的单元格编辑组件是QlineEdit,对输入的数据无法限制。可以为某列设置自定义代理组件,比如OcommoBox。在上面的bua中,希望把性别的编辑组件改成QcommoBox,只能选择某些项(比如男和女),而不能随便输入。


新建文件myDelegates.py,处理浮点数和下拉框的限定数据数据


注:每个自定义代理组件必须继承4个函数:

(1)createEditor:创建用于编辑模型数据的widget组件

(2) setEditData:从数据模型获取数据,供widget组件进行编辑

(3)setModelData:将widget上的数据更新到数据模型

(4)updateEditorGeometry:给widet组件设置合适的大小

在这个类中,用itemList来获取可以选的所有选项,比如男、女。然后限定只能使用这些选项。


from PyQt6.QtWidgets import QStyledItemDelegate,QDoubleSpinBox,QComboBox
from PyQt6.QtCore import Qt
##======================基于QComboBox的代理组件====
class QmyComboBoxDelegate(QStyledItemDelegate): 
   def __init__(self,parent=None):
       super().__init__(parent)
       self.__itemList=[]
       self.__isEditable=False
     
   def setItems(self, itemList, isEditable=False):
       self.__itemList=itemList
       self.__isEditable=isEditable
#自定义代理组件必须继承一下4个函数
   def createEditor(self, parent, option,index):
       editor=QComboBox(parent)
       editor.setFrame(False)
       editor.setEditable(self.__isEditable)
       editor.addItems(self.__itemList)
       return editor
     
   def setEditorData(self, editor, index):
      model=index.model()
      text=model.data(index, Qt.ItemDataRole.EditRole)
      editor.setCurrentText(text)
     
   def setModelData(self, editor,model, index):
      text=editor.currentText()
      model.setData(index, text, Qt.ItemDataRole.EditRole)
   def updateEditorGeometry(self,editor,option,index):
      editor.setGeometry(option.rect)
##====================基于QDoubleSpinbox的代理组件=======
#在这个类中,定义了_min,_max,_decimals,然后限定范围只能在_min和_max之间
class QmyFloatSpinDelegate(QStyledItemDelegate):
    def __init__(self,minV=0, maxV=10000, digi=2, parent=None):
        super().__init__(parent)
        self. __min=minV
        self.__max=maxV
        self.__decimals=digi
    def createEditor(self, parent, option,index):
        editor=QDoubleSpinBox(parent)
        editor.setFrame(False)
        editor.setRange(self.__min, self.__max)
        editor.setDecimals(self.__decimals)
        return editor
       
    def setEditorData(self,editor,index):
        model=index.model()#关联的数据模型
        text=model.data(index, Qt.EditRole)#单元格文字
        editor.setValue(float(text))
       
    def setModelData(self,editor,model,index):
        value=editor.value()
        model.setData(index,value, Qt.EditRole)
       
    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

 


注:从myDelegates.py文件中,import QmyComboBoxDelegate 这个类。


在myMainWindow中添加如下代码,上面的myMainWindow已经添加了,是完整的代码!


strList=("男", "女")
        self.__delegateSex=QmyComboBoxDelegate()
        self.__delegateSex.setItems(strList, False)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Gender"], self.__delegateSex)
       
        strList=("浙江","蒙古","陆西","吉林","广东","新疆")
        self.__delegateProvince=QmyComboBoxDelegate()
        self.__delegateProvince.setItems(strList,True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Province"], self.__delegateProvince)
       
        strList=("销售部", "技术部","生产部","行政部")
        self.__delegateDepart=QmyComboBoxDelegate()
        self.__delegateDepart.setItems(strList, True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"], self.__delegateDepart)

注:在Ui_MainWindow中需加入import res_rc


同时将res_rc.py中的


from PySide6 import QtCore


改为:from PyQt6 import QtCore


这样才能在运行窗口中显示图标


目录
相关文章
|
11月前
|
存储 关系型数据库 MySQL
mysql数据库删除的方式
用delete、truncate、drop命令进行删除,但是场景却不同
84 0
|
2月前
|
SQL 数据处理 定位技术
数据库基础(二):数据库表创建、修改、复制、删除与表数据处理
数据库基础(二):数据库表创建、修改、复制、删除与表数据处理
163 2
|
2月前
|
SQL 关系型数据库 MySQL
MYSQL基础知识之【创建,删除,选择数据库】
MYSQL基础知识之【创建,删除,选择数据库】
65 0
|
SQL 数据库 数据库管理
​数据库之定义删除修改基本表
​数据库之定义删除修改基本表
89 0
|
关系型数据库 MySQL 数据库
MySql基础-笔记2 -数据库创建、删除、选择等操作
MySql基础-笔记2 -数据库创建、删除、选择等操作
117 0
MySql基础-笔记2 -数据库创建、删除、选择等操作
|
存储 NoSQL Linux
数据库的创建和删除 | 学习笔记
快速学习 数据库的创建和删除
74 0
数据库的创建和删除 | 学习笔记
|
SQL 算法 安全
【MySQL】数据库视图的介绍、作用、创建、查看、删除和修改(附练习题)
文章目录 1 视图的介绍与作用 2 视图的创建 3 视图的修改 4 视图的更新 5 视图的重命名与删除 6 视图的练习 6.1 数据准备 6.2 查询平均分最高的学校名称 写在最后
【MySQL】数据库视图的介绍、作用、创建、查看、删除和修改(附练习题)
|
关系型数据库 MySQL 数据库
数据库学习-表的创建作业示例【带源码】
MySQL数据库 “表的创建 ” 习题示例,包含源码,能建立起对于表的创建的基本概念
139 0
数据库学习-表的创建作业示例【带源码】
|
关系型数据库 MySQL 数据库
数据库学习-新增数据作业示例【带源码】
MySQL数据库 “新增数据 ” 习题示例,包含源码,能建立起对于新增数据的基本概念
172 0
数据库学习-新增数据作业示例【带源码】
|
关系型数据库 MySQL 数据库
数据库学习-更新数据作业示例【带源码】
MySQL数据库 “更新数据” 习题示例,包含源码,能建立起对于如何更新数据的基本概念
141 0
数据库学习-更新数据作业示例【带源码】