- QTableModel能够实现数据按需加载,从而实现“大数据或无限数据”的动态加载,避免卡顿
实现过程简析
- QT提供了Model-View机制,来实现数据的管理和表格显示
- View会在特定条件下,调用Model的接口,实现相关模型数据的调用,调用过程不会拷贝数据,提高存储和运行效率
- rowCount()方法,作为model接口,被View调用,获得View要显示的总行数
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const,作为model接口,被View调用,返回数据的值,返回类型是值
- 当canFetchMore()被调用且返回值为true时,View会调用fetchMore(),更新View后续操作
- 在Qt中,canFetchMore()的调用机制与模型的数据加载策略密切相关,其触发条件及核心逻辑如下:
- 视图驱动加载,需要展示更多数据时,Qt框架会自动检测当前模型是否还有未加载的数据
- 滚动到底部:用户滚动到视图底部时,框架会调用canFetchMore()判断是否需要加载新数据。
- 树形结构展开:对于树形模型(如QTreeView),展开父节点时会触发canFetchMore(),检查该节点下是否有更多子数据。
- 模型数据状态判断,重写canFetchMore(),通过自定义逻辑返回true或false,决定是否触发fetchMore()加载数据
- 显示调用,手动触发fetchMore(),此时会隐式调用canFetchMore()进行验证
- 若需一次性获取全部数据:(如导出到文件)while (model->canFetchMore()) {}
- 后台预加载:在数据请求完成前预加载部分数据,优化用户体验
- 与UI交互的联动,滚动到底部时,通过
QScrollEvent
触发fetchMore()
QT官方示例分析(fetchmore)
int FileListModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : fileCount;
}
bool FileListModel::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid())
return false;
return (fileCount < fileList.size());
}
void FileListModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid()) return;
int remainder = fileList.size() - fileCount;
int itemsToFetch = qMin(100, remainder);
if (itemsToFetch <= 0) return;
beginInsertRows(QModelIndex(), fileCount, fileCount + itemsToFetch - 1);
fileCount += itemsToFetch;
endInsertRows();
emit numberPopulated(itemsToFetch);
}
void FileListModel::setDirPath(const QString &path)
{
QDir dir(path);
beginResetModel();
fileList = dir.entryList();
fileCount = 0;
endResetModel();
}
QVariant FileListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
if (index.row() >= fileList.size() || index.row() < 0) return QVariant();
if (role == Qt::DisplayRole) {
return fileList.at(index.row());
} else if (role == Qt::BackgroundRole) {
int batch = (index.row() / 100) % 2;
if (batch == 0)
return qApp->palette().base();
else
return qApp->palette().alternateBase();
}
return QVariant();
}
inline const T &QList<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::at", "index out of range");
return reinterpret_cast<Node *>(p.at(i))->t(); }