如何在不冻结主界面的情况下更新QStandartItemModel

2024-09-28 17:27:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我开始学习PyQt4了,我已经在某件事上耽搁了很长时间,自己都搞不懂:

这是一个概念:有一个带有定制的QStandartItemModel的TreeView,每隔几秒就会重建一次,可以有很多(至少数百个)条目,还有不同列的其他委托等等。这相当复杂,即使是没有委托的普通模型,构建时间也会达到0.3秒,这使得树景结冰了。在

请告诉我解决这个问题的最佳方法。我想在不同的线程中构建模型,并最终将其发送到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模型发生了什么,以及如何处理它,而且我的“应用程序”使用的内存似乎在不断增加。在

另一件事是我想保留我的选择,但是基于项目数据,而不是可视的矩形或行顺序,所以我也这么做了,但是它看起来太脏/太粗糙了,不是合适的方法。如有任何帮助,我们将不胜感激。代码如下:

^{pr2}$

Tags: 模型selfappsignaltimeinitdefreloader
1条回答
网友
1楼 · 发布于 2024-09-28 17:27:48

你的想法是对的。在

您需要一个单独的工作线程来为您重新计算模型(根据需要,基于时间或基于信号)。然后,当计算完成时,您需要连接一个信号来通知主线程。在

有几个陷阱你必须知道。在

  1. QObject存在于线程中。默认情况下,信号/时隙范例(至少在C++ QT)中工作在所有者线程中。如果要发送信号交叉线程,则需要明确地指定它(请参阅信号/连接文档)。

  2. 为了在工作线程中使用模型,您需要将模型“移动”到工作线程中(应该有一个名为movetothread或类似的方法)。

  3. 确保主线程和工作线程正确同步。

QT还有QFuture(不确定PyQT是否有),它可以用来在主线程中保存新模型,并在工作线程重新生成它时自动重新加载它。在

祝你好运。在

相关问题 更多 >