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

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

还有使用的说明手册

相关推荐
六月闻君几秒前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队9 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
nuclear201121 分钟前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组
inventecsh25 分钟前
mongodb基础操作
数据库·mongodb
白云如幻29 分钟前
SQL99版链接查询语法
数据库·sql·mysql
Lucky小小吴36 分钟前
有关django、python版本、sqlite3版本冲突问题
python·django·sqlite
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database
GIS 数据栈1 小时前
每日一书 《基于ArcGIS的Python编程秘笈》
开发语言·python·arcgis
爱分享的码瑞哥1 小时前
Python爬虫中的IP封禁问题及其解决方案
爬虫·python·tcp/ip
The_Ticker2 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程