为什么QListView比QListWidget慢?

3

我有一个变量,像下面的代码中的a,其中有很多数据。我想在QListWidget或QListView中显示这些数据。我一直在使用QListWidget,但它比QListView消耗更多的内存,所以我选择了QListView。

但是在下面的代码中,显示QListView的速度比QListWidget慢。有没有什么方法可以解决这个问题?

from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import time
app=QApplication([])
n=1000000

a=[]
for i in range(n):
     a.append('asfghjkg'+str(i))
class TodoModel(QtCore.QAbstractListModel):
    def __init__(self, todos=None):
        super(TodoModel, self).__init__()
        self.todos = todos or []

    def data(self, index, role):
        if role == Qt.DisplayRole:
            # See below for the data structure.
            return self.todos[index.row()]
            # Return the todo text only.

    def rowCount(self, index): 
        return len(self.todos)    


todos = a
model = TodoModel(todos)

t=time.time()
win1=QListView()
win1.setUniformItemSizes(True)
win1.setViewMode(1)
win1.setWrapping(False)
win1.setFlow(QListWidget.TopToBottom)
win1.setModel(model)
win1.show()
print('show1',time.time()-t)
t=time.time()
win2=QListWidget()
win2.setUniformItemSizes(True)
win2.addItems(a)
win2.show()
print('show2',time.time()-t)
app.exec_()

我的电脑输出结果为:

show1 5.374950885772705
show2 1.3125648498535156

(注意:原文即为中文,此处为翻译后的内容)

1
这不是一个好的分析代码性能的方式。使用类似 python -m cProfile -s cumtime yourcode.py 的命令运行你的代码,你就可以看到时间都花在哪里了。请注意,这并不仅仅是上面提到的对 rowCountlen 函数的数百万次调用。 - user9088793
1个回答

2
区别在于list-widget在C++中创建所有项目,而list-view必须在自定义模型中进行数百万次Python方法调用。一个扁平的、单列的树形视图比列表视图快约两倍,但仍然比列表小部件慢得多。为了获得更好的性能,您可以尝试实现fetchmore。但这样做的缺点是滚动非常缓慢,并且您不能轻松地在列表中导航(例如,直接转到最后一个项目)。它还使排序和过滤变得更加困难。
如果您的数据集确实只是一个简单的字符串列表,那么使用QStringListModel可以获得更好的性能。这是因为它比list-widget使用的基于项目的模型要简单得多(当然,它是用C++实现的,不像您的自定义模型)。如果我将以下代码添加到您的测试脚本中:
model2 = QStringListModel(todos)
t=time.time()
win3=QListView()
win3.setUniformItemSizes(True)
win3.setViewMode(1)
win3.setWrapping(False)
win3.setFlow(QListWidget.TopToBottom)
win3.setModel(model2)
win3.show()
print('show3',time.time()-t)

我在我的系统上得到了这个输出:

show1 2.2652294635772705
show2 0.4205465316772461
show3 0.10054779052734375

那么,在这种情况下,字符串列表模型比列表小部件快四倍以上。然而,如果您的实际要求比这更复杂,您应该考虑使用具有基于SQL的模型的数据库。"最初的回答"

请问您能否对“扁平化的树形视图应该比列表视图更快 - 但仍然比列表小部件慢。”发表评论?为什么扁平化的树形视图比列表视图更快?而为什么列表视图比列表小部件更快?这个说法中哪些内容适用于C++ Qt?它在Python Qt中是如何/为什么成立的?这与树有什么关系呢? - Johannes Schaub - litb
1
需要一种更强大的方法来衡量性能。请注意,在 OP 的代码中交换 win1 和 win2 部分并不会导致它们时间轮廓的简单交换。 - user9088793
一个没有子项的单列树形视图与列表视图完全等效。我使用相同的脚本进行了测试,当使用自定义模型和字符串列表模型时,它大约比列表视图快两倍。必须以不同的方式实现树形视图,因为使用自定义模型时只调用了约一半的Python方法。带有字符串列表模型的列表视图比列表小部件更快,因为列表小部件使用基于项的模型,这是不太高效的(例如,它消耗更多内存)。 - ekhumoro
@ekhumoro 您的方法是一个好主意,但它使用的内存几乎是纯 QList 视图模型的两倍。 - hpaalm
@hpaalm 你尝试过直接将字符串添加到模型中而不是先创建一个单独的列表吗?如果这没有任何区别,我想你只能接受权衡:更快的速度==更多的内存。 - ekhumoro
@ekhumoro 也许单列 QTableView 的性能与 QTreeView 相当甚至更好?QListView 支持的功能可能会拖慢它的速度,例如带换行的水平布局或基于图标的自由定位布局。 - Johannes Schaub - litb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接