Я начинаю изучать PyQt4, давно застрял на чем-то и сам не могу понять:
Вот концепция: существует TreeView с пользовательским QStandartItemModel, который перестраивается каждые пару секунд и может иметь много (не менее сотен) записей, также будут дополнительные делегаты для различных столбцов и т. Д. довольно сложный, и время построения даже простой модели без делегатов достигает 0,3 секунды, что заставляет TreeView зависать.
Пожалуйста, посоветуйте мне лучший подход к решению этой проблемы. Я думал о том, чтобы как-то построить модель в другом потоке и, в конце концов, отправить ее в TreeView, где он просто выполнит setModel () с новым, но не смог сделать это.
Вот код, который может немного проиллюстрировать проблему:
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_()
Спасибо за советы.
Вот ситуация, которую я получил до сих пор:
При каждом обновлении я строю новую модель и отправляю ее в TreeView ... это быстро, но я не знаю, что происходит с текущей моделью TreeView и как с ней работать, также кажется, что память используется моим «приложением» постоянно увеличивается.
Другое дело, что я хочу сохранить свой выбор, но на основе данных элемента, а не визуального прямоугольника или порядка строк, поэтому я тоже это сделал, но он выглядит слишком грязным / хакерским, чтобы быть правильным. Любая помощь в этом также будет оценена. Код следует:
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.moveToThread(self)
def run(self):
while True:
model = Model()
#model.connect(model, SIGNAL('status'), self.emitStat)
if model.build():
self.emit(SIGNAL('refresh'), model)
self.sleep(REFRESH)
def emitStat(self, stat):
self.emit(SIGNAL('status'), stat)
class Tree(QTreeView):
def __init__(self, parent=None):
QTreeView.__init__(self, parent)
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
def resetModel(self, model):
stTime = time.clock()
# gather old selection
oldSel = set()
currModel = self.model()
for index in self.selectedIndexes():
id = currModel.itemFromIndex(index).data().toString()
oldSel.add('%s'%id)
# setup new
self.setModel(model)
selModel = self.selectionModel()
for r in range(model.rowCount()):
item = model.item(r,0)
rowId = '%s' % item.data().toString()
if rowId in oldSel:
sel = QItemSelection(model.index(r,0), model.index(r,model.columnCount()-1))
selModel.select(sel, QItemSelectionModel.Select)
self.setSelectionModel(selModel)
self.emit(SIGNAL('status'), 'TV setModel: %03fs' % (time.clock() - stTime))
class Model(QStandardItemModel):
def __init__(self, viewer=None):
QStandardItemModel.__init__(self,None)
def build(self):
stTime = time.clock()
newRows = []
for r in range(1000):
row = []
var = QVariant('%d'%r)
for c in range(12):
item = QStandardItem('%s r%02dc%02d' % (time.strftime('%H"%M\'%S'), r,c))
item.setData(var)
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()
return True
w = QWidget()
w.setGeometry(200,200,800,600)
hb = QVBoxLayout(w)
tv = Tree()
sb = QStatusBar()
reloader = Reloader_Thread()
tv.connect(tv, SIGNAL('status'), sb.showMessage)
reloader.connect(reloader, SIGNAL('refresh'), tv.resetModel)
reloader.connect(reloader, SIGNAL('status'), sb.showMessage)
reloader.start()
hb.addWidget(tv)
hb.addWidget(sb)
w.show()
app.setStyle('plastique')
app.processEvents(QEventLoop.AllEvents)
app.aboutToQuit.connect(reloader.quit)
app.exec_()