我有一个基于模型的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_())