pyqt5:数据库上的数据更改后正确更新QTreeView

时间:2019-03-26 09:59:11

标签: python sqlite pyqt5 qtreeview qsortfilterproxymodel

我有一个基于模型的QTreeView,由QSortFilterProxyModel提供。

我在这里显示数据库中的行。双击我正在执行模式QDialog以编辑数据(用户可以执行CRUD操作,例如在SQLite数据库中创建新行,更新,删除等)。

在关闭编辑对话框时,焦点将返回到基础QTreeView。 现在,我想从数据库中刷新更改的数据。 一种方法是建立完整的模型并重新获取所有行,但是随后用户选择的单元格消失了,它非常慢,并且TreeView闪烁(因为我对宽度进行了一些列调整。)

在QSortFilterProxyModel上发出dataChanged信号似乎无济于事。

我能以某种方式告诉我的模型刷新或更新数据,而无需再次获取所有行吗?

完整的工作代码示例:

import sys
from PyQt5 import QtWidgets, QtCore, QtGui
import sqlite3
import re

def _human_key(key):
    key = key.lower()
    key = key.replace("ä", "ae").replace("ö", "oe").replace("ü", "ue").replace("ß", "ss")
    parts = re.split(r'(\d*\.\d+|\d+)', key, re.IGNORECASE)
    return parts

class HumanProxyModel(QtCore.QSortFilterProxyModel):
    def lessThan(self, source_left, source_right):
        data_left = source_left.data()
        data_right = source_right.data()
        if type(data_left) == type(data_right) == str:
            return _human_key(data_left) < _human_key(data_right)            
        return super(HumanProxyModel, self).lessThan(source_left, source_right)

class winMain(QtWidgets.QMainWindow):
    COL_ID, COL_NAME = range(2)    

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()        

        # create and assign model
        self.model = self.createModel(self)

        proxy = HumanProxyModel(self)
        proxy.setSourceModel(self.model)
        self.treeView.setModel(proxy)

        # create db with some data                
        self.conn = self.setupDb()

        # format and sort the treeView
        self.treeView.setRootIsDecorated(False)
        self.treeView.setSortingEnabled(True)
        self.treeView.sortByColumn(self.COL_ID, QtCore.Qt.AscendingOrder)
        self.treeView.setAlternatingRowColors(True)
        self.treeView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.treeView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)

        # display the main window
        self.show()

    def setupUi(self):
        self.setWindowTitle("PyQt5 QTreeView refresh problem demo")

        # add a data fetch button
        pbFetch = QtWidgets.QPushButton(self)
        pbFetch.setText("Fetch data")
        pbFetch.move(350, 20)
        pbFetch.clicked.connect(self.on_pbFetch_clicked)

        # add a reset button
        pbReset = QtWidgets.QPushButton(self)
        pbReset.setText("Reset")
        pbReset.move(450, 20)
        pbReset.clicked.connect(self.on_pbReset_clicked)

        # add QTreeView-Control
        self.treeView = QtWidgets.QTreeView(self)
        self.treeView.move(50, 100)
        self.treeView.resize(700, 300)
        self.treeView.doubleClicked.connect(self.on_treeView_doubleClicked)        

        self.resize(800,450)  # resize main window                       

    def on_pbFetch_clicked(self):        
        self.fetchData()

    def on_pbReset_clicked(self):
        print("on_pbReset_clicked() called.")
        self.reset()

    def setupDb(self):
        # create db and table
        con = sqlite3.connect(":memory:")
        con.execute("create table person(id int, name text)")                        
        # insert some example data
        con.execute("insert into person(id, name) values (1, 'anders')");
        con.execute("insert into person(id, name) values (2, 'Arachno')");
        con.execute("insert into person(id, name) values (3, 'Zabel')");
        con.execute("insert into person(id, name) values (4, 'Ötztürk')");
        con.execute("insert into person(id, name) values (5, 'de Hahn')");
        # commit the transaction
        con.commit()
        return con

    def reset(self):
        print("reset called.")
        self.model.beginResetModel()
        self.model.endResetModel()

    def fetchData(self):
        self.reset()

        cur = self.conn.cursor()
        sSql = "SELECT id, name FROM person"        
        rows = cur.execute(sSql)

        for row in rows:
            self.addPerson(self.model, row[0], row[1])

    def refresh_treeView(self):
        print("refresh_treeView() was called.")
        self.model.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())

    def createModel(self, parent):
        model = QtGui.QStandardItemModel(0, 2, parent)
        model.setHeaderData(self.COL_ID, QtCore.Qt.Horizontal, "ID")        
        model.setHeaderData(self.COL_NAME, QtCore.Qt.Horizontal, "Name")        
        return model

    def addPerson(self, model, personID, personName):
        model.insertRow(0)
        model.setData(model.index(0, self.COL_ID), personID)
        model.setData(model.index(0, self.COL_NAME), personName)

    def on_treeView_doubleClicked(self,index):
       row = index.row()
       ix = self.treeView.model().index(row, self.COL_ID)
       person_id = ix.data()
       print(f"id of double_clicked person: {person_id}")

       # create CRUD dialog for selected person
       self.disp_dlg_edit(person_id)       

    def disp_dlg_edit(self, person):        
       dlgEdit = QtWidgets.QDialog(self)

       lblId = QtWidgets.QLabel(dlgEdit)
       lblId.setText("ID:")       
       efId = QtWidgets.QLineEdit(dlgEdit)
       efId.setReadOnly(True)
       efId.setEnabled(False)
       efId.move(50, 0)

       lblName = QtWidgets.QLabel(dlgEdit)       
       lblName.setText("Name:")
       lblName.move(0, 25)
       efName = QtWidgets.QLineEdit(dlgEdit)       
       efName.move(50, 25)

       pbUpdate = QtWidgets.QPushButton(dlgEdit)
       pbUpdate.setText("Update")
       pbUpdate.move(200,0)
       pbUpdate.resize(100,50)              

       # fetch the data of given person
       cur = self.conn.cursor()
       sSql = "SELECT id, name FROM person WHERE id = ?"       
       cur.execute(sSql, (person,))
       result = cur.fetchone()
       person_id = result[0]
       efId.setText(str(person_id))
       person_name = result[1]
       efName.setText(person_name)

       pbUpdate.clicked.connect(lambda: self.update_person(person_id, efName.text()))

       dlgEdit.resize(300, 50)
       dlgEdit.exec_()

       self.refresh_treeView()

    def update_person(self, person_id, person_name):
        print(f"update_person({person_id}, {person_name}) called.")
        cur = self.conn.cursor()
        sSql = "UPDATE person set name=? WHERE ID=?"        
        cur.execute(sSql, (person_name,person_id,))
        self.conn.commit()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = winMain()
    sys.exit(app.exec_())

0 个答案:

没有答案