如何解决大型 QAbstractTableModel
我知道关于如何为 QTableView 设置行高的问题在 stackoverflow 上得到了很多回答。我再问一次,但我的问题并不完全是关于“如何”,至少不是那么简单。在从 Qt.SizeHintRole
派生的自定义模型的数据方法中,我在 QAbstractTableModel
的帮助下成功设置了行高 - 请参阅下面的代码。 (也尝试了非常相似的示例,但在 sizeHint()
的 qstyledItemDelegate
方法的帮助下 - 结果完全相同。)
当我有 MODEL_ROW_COUNT
大约 100 时,效果非常好,如下例所示。但是我的数据集有大约 30-40 万行。因此,这个简单的应用程序以 MODEL_ROW_COUNT=35000
为例,启动大约需要 30 秒。
这么大延迟的原因是这行代码:self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizetoContents)
如果我要评论这一行,一切都可以与 MODEL_ROW_COUNT=35000
一起快速运行。但在这种情况下,data()
方法未使用 Qt.SizeHintRole
调用,我无法操作行高。
所以,我的问题是 - 如何为具有数千行的数据集设置每行的行高?下面的示例有效,但需要 30 秒才能从 35 000 行开始(在窗口显示后一切都很流畅)...
同时,如果我使用 QsqlTableModel
它没有这个问题,我可以使用 sizeHint()
的 qstyledItemDelegate
没有大问题。但是有太多的委托是一团糟......我可以继承 qstyledItemDelegate
而不是 QAbstractTableModel
来实现我的自定义模型吗? (我不确定它是否会像每个源推荐的自定义模型的子类 QAbstractTableModel
一样工作......)
或者我做错了什么,还有比使用 QHeaderView.ResizetoContents
更好的方法?
附言我真的需要不同的高度。数据库中的某些行数据较少,我可能会在几个单元格中显示它们。但其他人有更多数据,我需要额外的空间来显示它。所有行的高度相同将意味着空间浪费(屏幕上有大量空白)或缺少某些数据行的基本细节。我使用常量 CUSTOM_ROW_HEIGHT
也只是让示例尽可能简单且易于重现 - 您可以将任何数据库与任何大表一起使用(我想即使没有数据库,我也可以重新创建它......会尝试很快)
from pyside2.QtWidgets import QApplication,QWidget,QVBoxLayout,QTableView,QHeaderView
from pyside2.Qtsql import QsqlDatabase,QsqlQuery
from pyside2.QtCore import Qt,QAbstractTableModel,QSize
class MyWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.db = QsqlDatabase.addDatabase("QsqlITE")
self.db.setDatabaseName("/home/db.sqlite")
self.db.open()
self.table_model = MyModel(parent=self,db=self.db)
self.table_view = QTableView()
self.table_view.setModel(self.table_model)
# SizeHint is not triggered without this line but it causes delay
self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizetoContents)
layout = QVBoxLayout(self)
layout.addWidget(self.table_view)
self.setLayout(layout)
class MyModel(QAbstractTableModel):
CUSTOM_ROW_HEIGHT = 300
MODEL_ROW_COUNT = 100
MODEL_COL_COUNT = 5
def __init__(self,parent,db):
QAbstractTableModel.__init__(self,parent)
self.query = QsqlQuery(db)
self.query.prepare("SELECT * FROM big_table")
self.query.exec_()
def rowCount(self,parent=None):
return self.MODEL_ROW_COUNT
def columnCount(self,parent=None):
return self.MODEL_COL_COUNT
def data(self,index,role=Qt.displayRole):
if not index.isValid():
return None
if role == Qt.displayRole:
if self.query.seek(index.row()):
return str(self.query.value(index.column()))
if role == Qt.SizeHintRole:
return QSize(0,self.CUSTOM_ROW_HEIGHT)
return None
def main():
app = QApplication([])
win = MyWindow()
win.show()
app.exec_()
if __name__ == "__main__":
main()
解决方法
好的,感谢@musicamante,我意识到我错过了 canFetchMore()
和 fetchMore()
方法。因此,我在 MyModel
类中实现了动态大小属性和这些方法。这一点都不难,现在我拥有比 QSqlTableModel
更好的性能和相同的视觉行为,直接控制可见缓冲区大小。下面是 MyModel
类的新代码:
class MyModel(QAbstractTableModel):
CUSTOM_ROW_HEIGHT = 300
MODEL_ROW_COUNT = 37000
MODEL_COL_COUNT = 5
PAGE_SIZE = 500
def __init__(self,parent,db):
QAbstractTableModel.__init__(self,parent)
self.query = QSqlQuery(db)
self.query.prepare("SELECT * FROM big_table")
self.query.exec_()
self._current_size = self.PAGE_SIZE
def rowCount(self,parent=None):
return self._current_size
def columnCount(self,parent=None):
return self.MODEL_COL_COUNT
def data(self,index,role=Qt.DisplayRole):
if not index.isValid():
return None
if role == Qt.DisplayRole:
if self.query.seek(index.row()):
return str(self.query.value(index.column()))
if role == Qt.SizeHintRole:
return QSize(0,self.CUSTOM_ROW_HEIGHT)
return None
def canFetchMore(self,index):
return self._current_size < self.MODEL_ROW_COUNT
def fetchMore(self,index):
self.beginInsertRows(index,self._current_size,self._current_size + self.PAGE_SIZE - 1)
self._current_size += self.PAGE_SIZE
self.endInsertRows()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。