У меня есть QTreeView на основе модели, который подается QSortFilterProxyModel.
Здесь я отображаю строки из базы данных.Двойным щелчком я выполняю модальный QDialog для редактирования данных (пользователь может выполнять операции CRUD, такие как создание новых строк в моей базе данных SQLite, обновления, удаление и т. Д.).
При закрытии edit-В диалоговом окне фокус возвращается к базовому QTreeView.Теперь я хотел бы обновить измененные данные из базы данных.Один из способов сделать это состоит в том, чтобы создать мою полную модель и повторно выбрать все строки, но затем выбранная пользователем ячейка исчезает, и она очень медленная, а также мерцает TreeView (потому что я делаю некоторые настройки столбца относительно ширины.)
Передача сигнала dataChanged на QSortFilterProxyModel как-то, кажется, делает ... ничего.
Могу ли я как-то сказать моей модели обновить или обновить данные, не выбирая строки alls снова?
пример полного рабочего кода:
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_())