QTreeView展开SSHFS挂载目录大节点时,如何显示忙碌状态?
解决QTreeView展开SSHFS目录延迟时的忙碌光标提示问题
核心思路
首次展开大目录的延迟源于SSHFS远程文件系统的IO操作阻塞了UI线程,我们需要在目录开始加载时切换为忙碌光标,加载完成后恢复正常光标。关键是利用模型的加载状态信号,而非仅依赖视图的展开信号。
针对QFileSystemModel的解决方案
如果使用Qt内置的QFileSystemModel,它自带directoryLoaded信号,可精准捕获目录加载完成的时机:
方法1:信号槽连接(无需重写视图)
// 成员变量,跟踪忙碌光标引用计数,避免多加载场景下光标异常 int m_waitCursorCount = 0; // 连接视图展开信号,触发忙碌光标 connect(m_treeView, &QTreeView::expanded, this, [=](const QModelIndex& index) { auto fsModel = qobject_cast<QFileSystemModel*>(m_treeView->model()); if (!fsModel || !fsModel->isDir(index)) return; QString dirPath = fsModel->filePath(index); // 仅对未加载的目录设置光标 if (!fsModel->directoryLoaded(dirPath)) { m_waitCursorCount++; if (m_waitCursorCount == 1) { QApplication::setOverrideCursor(Qt::WaitCursor); } } }); // 连接模型加载完成信号,恢复光标 connect(fsModel, &QFileSystemModel::directoryLoaded, this, [=](const QString&) { if (m_waitCursorCount > 0) { m_waitCursorCount--; if (m_waitCursorCount == 0) { QApplication::restoreOverrideCursor(); } } });
方法2:重写QTreeView的setExpanded方法
如果希望逻辑封装在视图内部,可继承QTreeView并重写setExpanded:
class SSHTreeView : public QTreeView { Q_OBJECT public: using QTreeView::QTreeView; protected: void setExpanded(const QModelIndex& index, bool expand) override { if (expand) { auto fsModel = qobject_cast<QFileSystemModel*>(model()); if (fsModel && fsModel->isDir(index)) { QString dirPath = fsModel->filePath(index); if (!fsModel->directoryLoaded(dirPath)) { QApplication::setOverrideCursor(Qt::WaitCursor); // 单次连接,加载完成后自动断开 connect(fsModel, &QFileSystemModel::directoryLoaded, this, [=](const QString& loadedPath) { if (loadedPath == dirPath) { QApplication::restoreOverrideCursor(); } }, Qt::SingleShotConnection); } } } // 调用父类方法执行实际展开逻辑 QTreeView::setExpanded(index, expand); } };
针对自定义模型的解决方案
如果使用自定义目录模型,需要在模型中添加两个信号:
class CustomDirModel : public QAbstractItemModel { Q_OBJECT signals: void loadingStarted(const QModelIndex& index); // 开始加载子项时发出 void loadingFinished(const QModelIndex& index); // 加载完成时发出 // ... 其他模型逻辑 };
然后在视图中连接这两个信号:
connect(m_customModel, &CustomDirModel::loadingStarted, this, [=]() { QApplication::setOverrideCursor(Qt::WaitCursor); }); connect(m_customModel, &CustomDirModel::loadingFinished, this, [=]() { QApplication::restoreOverrideCursor(); });
关键注意事项
- 利用
QApplication::setOverrideCursor和restoreOverrideCursor的栈式特性,确保光标状态正确恢复,避免多加载场景下光标异常。 - 仅对未加载的目录设置光标,避免重复触发(比如已加载的目录再次展开时无需提示)。
内容的提问来源于stack exchange,提问作者SixDegrees
相关产品推荐
相关产品推荐

