Pyqt Model View 的使用方法

python 复制代码
class CheckBoxDeleta(QAbstractItemDelegate):
    def __init__(self, parent: QObject | None = ...) -> None:
        super().__init__(parent)
    
    def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex) -> QWidget:
        return super().createEditor(parent, option, index)
    
    def setEditorData(self, editor: QWidget, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().setEditorData(editor, index)
    
    def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().setModelData(editor, model, index)
    
    def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().updateEditorGeometry(editor, option, index)

class TableModel(QAbstractTableModel):
    def __init__(self, parent: QObject | None = ...) -> None:
        super(TableModel,self).__init__()
    
    # paint row
    def rowCount(self, parent: QModelIndex | QPersistentModelIndex = ...) -> int:
        return 12
    
    # paint col
    def columnCount(self, parent: QModelIndex | QPersistentModelIndex = ...) -> int:
        return 12
    
    # Data to View Change and Save data
    def setData(self, index: QModelIndex | QPersistentModelIndex, value: Any, role: int = ...) -> bool:
        print(f"row:{index.row()} col:{index.column()} value:{value} ")
        return True

    # Init Data
    def data(self, index: QModelIndex | QPersistentModelIndex, role: int = ...) -> Any:
        return 12

    def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> Any:
        return super().headerData(section, orientation, role)
    
    #Table Can Selected and Checked
    def flags(self, index: QModelIndex | QPersistentModelIndex) -> Qt.ItemFlag:
        return Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled

#TODO:User define functions
class QSqlTableModelV2(QSqlTableModel):
    __changed__={}
    def __init__(self, parent, db) -> None:
        super().__init__(parent, db)
    
    def changedList(self)->dict:
        return self.__changed__
    
    def setRemoteData(self):
        pass

    def setData(self, index: QModelIndex | QPersistentModelIndex, value: Any, role: int = ...) -> bool:
        self.__changed__[self.data(index.sibling(index.row(),0),Qt.ItemDataRole.DisplayRole)]=value
        return super().setData(index, value, role) #Commit to database
 
    #Set data
    def data(self, idx: QModelIndex | QPersistentModelIndex, role: int = ...) -> Any:
        print("data row:%d col:%d"%(idx.row(),idx.column()))
        return super().data(idx, role)

    def submitAll(self) -> bool:
        return super().submitAll()
    
    def submit(self) -> bool:
        self.__changed__.clear()
        return super().submit()
    
    def revertAll(self) -> None:
        self.__changed__.clear()
        return super().revertAll()

全是嵌套的callback 的实现方法,层级分离,通过类的继承,拓展基础类的功能,通用性不错,省了自己在,调用原始方法,构建view 和 控制数据库,再将数据同步到板卡,利用现成的基础类,自己在拓展一个功能就🆗了
C 没有继承和多态,一言难尽,Python 的继承和多态应该是最容易理解的
添加复选框的方法(大体上只能说有这么一个功能,还有一些细节上的问题)

python 复制代码
class QSqlTableModelV2(QSqlTableModel):
    __changed__={}
    def __init__(self, parent,DB) -> None:
        super().__init__(parent,DB)
    
    def data(self, idx: QModelIndex | QPersistentModelIndex, role: int = ...) -> Any:
        if idx.column() != 0:
            return super().data(idx, role)
        else:
            if self.__changed__.get(idx.row()) is not None: 
                self.__changed__[idx.row()][1]=super().data(idx,role)
                if self.__changed__[idx.row()][0] == Qt.CheckState.Checked:
                    return Qt.CheckState.Checked
                else:
                    return Qt.CheckState.Unchecked
            else:
                return Qt.CheckState.Unchecked

    def setData(self, index: QModelIndex | QPersistentModelIndex, value: Any, role: int = ...) -> bool:
        if role == Qt.ItemDataRole.CheckStateRole and index.column() ==0:
            if value == Qt.CheckState.Checked.value:
                self.__changed__[index.row()]=[Qt.CheckState.Checked,super().data(index,role),index.sibling(index.row(),3).data()]
            elif value == Qt.CheckState.Unchecked.value:
                self.__changed__[index.row()]=[Qt.CheckState.Unchecked,0,0]
            return True
        else:
            return super().setData(index, value, role)

    def flags(self, index: QModelIndex | QPersistentModelIndex) -> Qt.ItemFlag:
        _flags = super().flags(index)
        if index.column() in [1,2,4,5,6,7,8,9]:
            _flags =_flags&(~Qt.ItemFlag.ItemIsEditable)
        elif index.column() == 0:
            _flags = Qt.ItemFlag.ItemIsUserCheckable|Qt.ItemFlag.ItemIsEnabled|Qt.ItemFlag.ItemIsSelectable|Qt.ItemFlag.ItemIsEditable
        return _flags
      
    
    def checkedTable(self) -> dict:
        return self.__changed__
python 复制代码
    def flags(self, index: QModelIndex | QPersistentModelIndex) -> Qt.ItemFlag:
        _flags = super().flags(index)
        if index.sibling(index.row(),2).data() == "RO" or index.column() != self.__EditCol__:
            _flags =_flags&(~Qt.ItemFlag.ItemIsEditable)
        return _flags
    

装饰器的优势

python 复制代码
def QuestionBox(msg:str):
        def Msg(func):
            def init(parent=None):
                if QMessageBox.question(parent,"参数发生了变化","%s"%msg) == QMessageBox.StandardButton.Yes:
                    func(parent)
            return init
        return Msg

 @QuestionBox("确认保存?")
    def actSave(self):
        print(self.__tableModel__.checkWrite())
        self.__tableModel__.clearCheckWrite()
        if self.__tableModel__.submitAll():
            QMessageBox.information(self,"Operator Save","Successful")
        else:
            QMessageBox.critical(self,"Operator Save","Failed")

    @QuestionBox("确认取消?")
    def actAdd(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.insertRow(self.__tableModel__.rowCount()-1,1)
        self.__selModel__.clearSelection()
        self.__selModel__.setCurrentIndex(curIndex,QItemSelectionModel.SelectionFlag.Select)

    @QuestionBox("确认删除")
    def actDelete(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.removeRow(curIndex.row())

    @QuestionBox("确认插入?")
    def actInsert(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.insertRow(curIndex.row(),QModelIndex())
        self.__selModel__.clearSelection()
        self.__selModel__.setCurrentIndex(curIndex,QItemSelectionModel.SelectionFlag.Select)

    @QuestionBox("确认取消?")
    def actCancel(self):
        if self.__tableModel__.revertAll():
            QMessageBox.information(self,"Operator Cancel","Successful")
        else:
            QMessageBox.critical(self,"Operator Cancel","Failed")

一个完整的练习及操作方法

python 复制代码
from typing import Any, Dict, Optional, Union
from PySide6.QtCore import *
import PySide6.QtCore
import PySide6.QtSql
from PySide6.QtWidgets import *
from PySide6.QtSql import *
from PySide6.QtGui import *
import PySide6.QtWidgets

from tableView_ui import Ui_MainWindow
import sys
import time

class CheckBoxDeleta(QAbstractItemDelegate):
    def __init__(self, parent: QObject | None = ...) -> None:
        super().__init__(parent)
    
    def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex) -> QWidget:
        return super().createEditor(parent, option, index)
    
    def setEditorData(self, editor: QWidget, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().setEditorData(editor, index)
    
    def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().setModelData(editor, model, index)
    
    def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex) -> None:
        return super().updateEditorGeometry(editor, option, index)

class TableModel(QAbstractTableModel):
    def __init__(self, parent: QObject | None = ...) -> None:
        super(TableModel,self).__init__()
    
    # paint row
    def rowCount(self, parent: QModelIndex | QPersistentModelIndex = ...) -> int:
        return 12
    
    # paint col
    def columnCount(self, parent: QModelIndex | QPersistentModelIndex = ...) -> int:
        return 12
    
    # Data to View Change and Save data
    def setData(self, index: QModelIndex | QPersistentModelIndex, value: Any, role: int = ...) -> bool:
        print(f"row:{index.row()} col:{index.column()} value:{value} ")
        return True

    # Init Data
    def data(self, index: QModelIndex | QPersistentModelIndex, role: int = ...) -> Any:
        return 12

    def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> Any:
        return super().headerData(section, orientation, role)
    
    #Table Can Selected and Checked
    def flags(self, index: QModelIndex | QPersistentModelIndex) -> Qt.ItemFlag:
        return Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled

class SelectedPara:
    state:Qt.CheckState
    indexForDB:str
    idx:QModelIndex
    def __init__(self,_st,id,idx) -> None:
        self.state=_st
        self.indexForDB=id
        self.idx=idx

#TODO:User define functions
class QSqlTableModelV2(QSqlTableModel):
    __EditCol__=2
    __checkList__={}
    __preValue__:Any
    __querry__:str
    __ro__:int = 0
    def __init__(self, parent,DB) -> None:
        super().__init__(parent,DB)
    
    def setColumQuerry(self,columName:str):
       self.__querry__ = columName 

    def setEditColumn(self,col:int):
        self.__EditCol__=col

    def setData(self, index: QModelIndex | QPersistentModelIndex, value: Any, role: int = ...) -> bool:
        self.__checkList__[index.sibling(index.row(),0).data()]=value
        return super().setData(index, value, role)

    def selectStatement(self) -> str:
        return "SELECT %s from %s"%(self.__querry__,self.tableName())

    def checkWrite(self):
        return self.__checkList__

    def setReadonly(self,ro:int):
        self.__ro__ = ro

    def clearCheckWrite(self):
        self.__checkList__.clear()

    def flags(self, index: QModelIndex | QPersistentModelIndex) -> Qt.ItemFlag:
        _flags = super().flags(index)
        if index.sibling(index.row(),self.__ro__).data() == "RO" or index.column() != self.__EditCol__:
            _flags =_flags&(~Qt.ItemFlag.ItemIsEditable)
        return _flags

def QuestionBox(msg:str):
        def Msg(func):
            def init(parent=None):
                if QMessageBox.question(parent,"参数发生了变化","%s"%msg) == QMessageBox.StandardButton.Yes:
                    func(parent)
            return init
        return Msg
    
class MainWindow(QMainWindow):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.ui=Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.select.clicked.connect(self.InitTable)
        self.ui.open.clicked.connect(self.OpenDatabase)
        self.ui.actionSave.triggered.connect(self.actSave)
        self.ui.actionCancel.triggered.connect(self.actCancel)
        self.ui.actionDelete.triggered.connect(self.actDelete)
        self.ui.actionadd.triggered.connect(self.actAdd)
        self.ui.actionInsert.triggered.connect(self.actInsert)

        self.__handle__=QSqlDatabase.addDatabase("QSQLITE")
        self.__tableModel__=QSqlTableModelV2(self,self.__handle__)
        self.ui.tableView.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
        self.__tableModel__.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
        self.ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
        self.ui.tableView.setModel(self.__tableModel__)
        self.__selModel__=QItemSelectionModel(self.__tableModel__)
        self.__selModel__.currentRowChanged.connect(self.do_currentChanged)
        self.ui.tableView.setSelectionModel(self.__selModel__)
        self.__tableModel__.setColumQuerry("ID,name,mode,V0")
        self.__tableModel__.setReadonly(2)
        self.__tableModel__.setEditColumn(3)
    
    def do_currentChanged(self,cur:QModelIndex,pre:QModelIndex):
        print("hello world")
    
    def OpenDatabase(self):
        self.__dbName__=self.ui.lineEdit
        dbName,flt=QFileDialog.getOpenFileName(self,"Select Database File","","SQLITE DB(*.db)")
        self.__dbName__.setText(dbName)
        if dbName == "":
            return
        self.__handle__.setDatabaseName(dbName)
        self.ui.comboBox.clear()
        if self.__handle__.open() is not False:
            rec=self.__handle__.exec("select * from sqlite_master where type='table'")
            while rec.next():
                self.ui.comboBox.addItem(str(rec.value(1)))
                
    @QuestionBox("确认保存?")
    def actSave(self):
        print(self.__tableModel__.checkWrite())
        self.__tableModel__.clearCheckWrite()
        if self.__tableModel__.submitAll():
            QMessageBox.information(self,"Operator Save","Successful")
        else:
            QMessageBox.critical(self,"Operator Save","Failed")

    @QuestionBox("确认增加?")
    def actAdd(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.insertRow(self.__tableModel__.rowCount()-1,1)
        self.__selModel__.clearSelection()
        self.__selModel__.setCurrentIndex(curIndex,QItemSelectionModel.SelectionFlag.Select)

    @QuestionBox("确认删除?")
    def actDelete(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.removeRow(curIndex.row())

    @QuestionBox("确认插入?")
    def actInsert(self):
        curIndex=self.__selModel__.currentIndex()
        self.__tableModel__.insertRow(curIndex.row(),QModelIndex())
        self.__selModel__.clearSelection()
        self.__selModel__.setCurrentIndex(curIndex,QItemSelectionModel.SelectionFlag.Select)

    @QuestionBox("确认取消?")
    def actCancel(self):
        if self.__tableModel__.revertAll():
            QMessageBox.information(self,"Operator Cancel","Successful")
        else:
            QMessageBox.critical(self,"Operator Cancel","Failed")

    def InitTable(self):
       self.__tableModel__.setTable(self.ui.comboBox.currentText())
       if self.__tableModel__.select():
            QMessageBox.information(self,"Operator Cancel","Successful")
       else:
            QMessageBox.critical(self,"Operator Cancel","Failed")
           
if __name__ == "__main__":
    app=QApplication(sys.argv)
    Window=MainWindow()
    Window.show()
    app.exit(app.exec())

界面定稿, 剩下的局势补充,交互逻辑,测试逻辑,还有一些合适的图标需要补充

还有使用的说明手册

相关推荐
chao_7895 分钟前
链表题解——两两交换链表中的节点【LeetCode】
数据结构·python·leetcode·链表
傻啦嘿哟11 分钟前
Python 数据分析与可视化实战:从数据清洗到图表呈现
大数据·数据库·人工智能
cookqq38 分钟前
mongodb源码分析session异步接受asyncSourceMessage()客户端流变Message对象
数据库·sql·mongodb·nosql
呼拉拉呼拉1 小时前
Redis故障转移
数据库·redis·缓存·高可用架构
大霞上仙1 小时前
nonlocal 与global关键字
开发语言·python
什么都想学的阿超1 小时前
【Redis系列 04】Redis高可用架构实战:主从复制与哨兵模式从零到生产
数据库·redis·架构
pp-周子晗(努力赶上课程进度版)1 小时前
【MySQL】视图、用户管理、MySQL使用C\C++连接
数据库·mysql
Mark_Aussie1 小时前
Flask-SQLAlchemy使用小结
python·flask
斯特凡今天也很帅1 小时前
clickhouse常用语句汇总——持续更新中
数据库·sql·clickhouse
程序员阿龙2 小时前
【精选】计算机毕业设计Python Flask海口天气数据分析可视化系统 气象数据采集处理 天气趋势图表展示 数据可视化平台源码+论文+PPT+讲解
python·flask·课程设计·数据可视化系统·天气数据分析·海口气象数据·pandas 数据处理