How to update QStandartItemModel without freezing the main UI
- by user1044002
I'm starting to learn PyQt4 and have been stuck on something for a long time now and can't figure it out myself:
Here is the concept: There is a TreeView with custom QStandartItemModel, which gets rebuild every couple of seconds, and can have a lot (hundreds at least) of entries, there also will be additional delegates for the different columns etc. It's fairly complex and the building time for even plain model, without delegates, goes up to .3 sec, which makes the TreeView to freeze.
Please advice me for the best approach on solving this. I was thing of somehow building the model in different thread, and eventually sending it to the TreeView, where it would just perform setModel() with the new one, but couldn't make that work.
here is some code that may illustrate the problem a bit:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os, re, time
app = QApplication(sys.argv)
REFRESH = 1
class Reloader_Thread(QThread):
def __init__(self, parent = None):
QThread.__init__(self, parent)
self.loaders = ['\\', '--', '|', '/', '--']
self.emit(SIGNAL('refresh'))
def run(self):
format = '|%d/%b/%Y %H:%M:%S| '
while True:
self.emit(SIGNAL('refresh'))
self.sleep(REFRESH)
class Model(QStandardItemModel):
def __init__(self, viewer=None):
QStandardItemModel.__init__(self,None)
self.build()
def build(self):
stTime = time.clock()
newRows = []
for r in range(1000):
row = []
for c in range(12):
item = QStandardItem('%s %02d%02d' % (time.strftime('%H"%M\'%S'), r,c))
row.append(item)
newRows.append(row)
eTime = time.clock() - stTime
outStr = 'Build %03f' % eTime
format = '|%d/%b/%Y %H:%M:%S| '
stTime = time.clock()
self.beginRemoveRows(QModelIndex(), 0, self.rowCount())
self.removeRows(0, self.rowCount())
self.endRemoveRows()
eTime = time.clock() - stTime
outStr += ', Remove %03f' % eTime
stTime = time.clock()
numNew = len(newRows)
for r in range(numNew):
self.appendRow(newRows[r])
eTime = time.clock() - stTime
outStr += ', Set %03f' % eTime
self.emit(SIGNAL('status'), outStr)
self.reset()
w = QWidget()
w.setGeometry(200,200,800,600)
hb = QVBoxLayout(w)
tv = QTreeView()
tvm = Model(tv)
tv.setModel(tvm)
sb = QStatusBar()
reloader = Reloader_Thread()
tvm.connect(tvm, SIGNAL('status'), sb.showMessage)
reloader.connect(reloader, SIGNAL('refresh'), tvm.build)
reloader.start()
hb.addWidget(tv)
hb.addWidget(sb)
w.show()
app.setStyle('plastique')
app.processEvents(QEventLoop.AllEvents)
app.aboutToQuit.connect(reloader.quit)
app.exec_()