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())

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

还有使用的说明手册

相关推荐
这个DBA有点耶8 小时前
NULL不是空——数据库里最反直觉的设计,90%新人踩过的坑
数据库·mysql·代码规范
用户8356290780518 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户8356290780518 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
这个DBA有点耶10 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
镜舟科技10 小时前
Databricks 再提 LTAP,AI 时代的数据底座为何重回大一统叙事?
数据库·架构·agent
Databend11 小时前
从湖仓升级为 Agent 时代的数据控制面,Snowflake 和 Databricks 有哪些布局
大数据·数据库·agent
ClouGence14 小时前
SQL Server CDC 能放到 Always On 备库读吗?一文讲透原理与实践
数据库·sql server
你好潘先生16 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
Agent_大师16 小时前
WebSocket 行情重连成功,K线缺口不会自动消失
python
荣码16 小时前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python