文章目錄
- 一、QFileSystemModel的基本介紹
- 二、QFileSystemModel的基本使用
- 2.1 在 QTreeView 中使用
- 2.2 在 QListView 中使用
- 2.3 在 QTableView 中使用
- 三、QFileSystemModel的常用API
- 3.1 設置根目錄
- 3.2 過濾文件
- 3.2.1 僅顯示文件
- 3.2.2 只顯示特定后綴的文件
- 3.2.3 只顯示目錄
- 四、監聽文件系統變化
- 1. QFileSystemModel常見信號
- 2. 信號的使用示例
- 2.1 監聽目錄加載完成
- 2.2 監聽文件重命名
- 2.3 監聽根路徑變化
- 2.4 監聽文件/目錄添加
- 2.5 監聽文件/目錄刪除
- 3. 動態更新QLabel顯示選中文件
- 4.右鍵菜單的實現
- 五、繼承QFileSystemModel并進行自定義
一、QFileSystemModel的基本介紹
??QFileSystemModel 是 Qt 框架中用于管理和顯示本地文件系統的 MVC 結構中的 Model。它可以與 QTreeView、QListView 或 QTableView 結合使用,實現文件管理功能。相比 QDirModel,QFileSystemModel 只會加載需要的目錄,支持懶加載,在處理大文件夾時更高效。
主要特點:
- 繼承自 QAbstractItemModel,提供標準的文件系統數據模型。
- 懶加載(Lazy Loading):不會一次性加載整個文件系統,只會加載需要的部分,提升性能。
- 支持文件過濾(setFilter()、setNameFilters())。
- 自動監聽文件系統變化,實時更新 UI。
二、QFileSystemModel的基本使用
2.1 在 QTreeView 中使用
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>int main(int argc, char *argv[]) {QApplication app(argc, argv);QFileSystemModel model;model.setRootPath(QDir::homePath()); // 設置根目錄QTreeView treeView;treeView.setModel(&model);treeView.setRootIndex(model.index(QDir::homePath())); // 綁定視圖treeView.show();return app.exec();
}
2.2 在 QListView 中使用
QListView listView;
listView.setModel(&model);
listView.setRootIndex(model.index(QDir::homePath()));
listView.show();
2.3 在 QTableView 中使用
QTableView tableView;
tableView.setModel(&model);
tableView.setRootIndex(model.index(QDir::homePath()));
tableView.show();
三、QFileSystemModel的常用API
3.1 設置根目錄
model.setRootPath(QDir::homePath()); // 設置為用戶目錄
注意:setRootPath() 只是設置數據模型的根目錄,并不會影響 QTreeView 顯示的目錄。要限制 QTreeView 的顯示范圍,需使用 setRootIndex()。
3.2 過濾文件
3.2.1 僅顯示文件
model.setFilter(QDir::Files | QDir::NoDotAndDotDot);
QDir::Files 只顯示文件,QDir::NoDotAndDotDot 過濾掉 . 和 … 目錄。
3.2.2 只顯示特定后綴的文件
model.setNameFilters(QStringList() << "*.cpp" << "*.h");
model.setNameFilterDisables(false); // 過濾掉不符合的文件
這將只顯示 .cpp 和 .h 文件。
3.2.3 只顯示目錄
model.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
只顯示目錄,隱藏所有文件。
四、監聽文件系統變化
1. QFileSystemModel常見信號
2. 信號的使用示例
2.1 監聽目錄加載完成
當 QFileSystemModel 完成某個目錄的加載時,可以使用 directoryLoaded() 信號:
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>
#include <QDebug>int main(int argc, char *argv[]) {QApplication app(argc, argv);QFileSystemModel model;QObject::connect(&model, &QFileSystemModel::directoryLoaded, [](const QString &path) {qDebug() << "目錄加載完成:" << path;});model.setRootPath(QDir::homePath());QTreeView treeView;treeView.setModel(&model);treeView.setRootIndex(model.index(QDir::homePath()));treeView.show();return app.exec();
}
解釋:
- 當某個目錄的內容加載完成時,會輸出 “目錄加載完成:/home/user”(Linux/macOS)或 “目錄加載完成:C:/Users/xxx”(Windows)。
- 適用場景:可以在目錄加載完成后執行額外的操作,比如統計文件數量、更新 UI 狀態等。
2.2 監聽文件重命名
如果用戶在文件管理器中修改了文件名,可以捕獲 fileRenamed() 信號:
QObject::connect(&model, &QFileSystemModel::fileRenamed, [](const QString &path, const QString &oldName, const QString &newName) {qDebug() << "文件重命名:" << path + "/" + oldName << " -> " << newName;});
解釋:
- fileRenamed(path, oldName, newName) 提供了文件所在目錄、舊文件名和新文件名。
- 適用場景:可以記錄日志、同步到數據庫或通知 UI 更新。
2.3 監聽根路徑變化
當 setRootPath() 發生變化時,觸發 rootPathChanged():
QObject::connect(&model, &QFileSystemModel::rootPathChanged, [](const QString &newPath) {qDebug() << "根目錄更改為:" << newPath;});
適用場景:當用戶更改文件瀏覽的根目錄時,可以執行特定操作,比如清除舊數據、更新 UI 等。
2.4 監聽文件/目錄添加
當新文件或目錄被創建時,會觸發 rowsInserted() 信號:
QObject::connect(&model, &QFileSystemModel::rowsInserted, [&model](const QModelIndex &parent, int start, int end) {for (int row = start; row <= end; ++row) {QModelIndex index = model.index(row, 0, parent);qDebug() << "新文件/文件夾:" << model.filePath(index);}});
解釋:
- rowsInserted() 觸發時,會輸出新文件或目錄的路徑。
- 適用場景:當用戶創建新文件/文件夾時,自動執行相應的 UI 更新或日志記錄。
2.5 監聽文件/目錄刪除
當某個文件或文件夾被刪除時,會觸發 rowsRemoved() 信號:
QObject::connect(&model, &QFileSystemModel::rowsRemoved, [](const QModelIndex &parent, int start, int end) {qDebug() << "文件/文件夾刪除:" << start << "到" << end;});
3. 動態更新QLabel顯示選中文件
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>
#include <QItemSelectionModel>int main(int argc, char *argv[]) {QApplication app(argc, argv);QFileSystemModel model;model.setRootPath(QDir::homePath());QTreeView treeView;treeView.setModel(&model);treeView.setRootIndex(model.index(QDir::homePath()));QLabel label;label.setText("選中文件路徑顯示區域");// 監聽選中項變化QObject::connect(treeView.selectionModel(), &QItemSelectionModel::selectionChanged, [&model, &treeView, &label](const QItemSelection &selected, const QItemSelection &) {if (!selected.indexes().isEmpty()) {QModelIndex index = selected.indexes().first();label.setText(model.filePath(index));}});// 設置 UI 布局QWidget window;QVBoxLayout layout;layout.addWidget(&treeView);layout.addWidget(&label);window.setLayout(&layout);window.show();return app.exec();
}
輸出顯示:
4.右鍵菜單的實現
可以為 QTreeView 添加右鍵菜單,實現文件操作(打開、刪除等)。
#include <QMenu>
#include <QAction>
#include <QDesktopServices>
#include <QUrl>void onContextMenu(const QPoint &pos) {QModelIndex index = treeView.indexAt(pos);if (!index.isValid()) return;QMenu menu;QAction *openAction = new QAction("打開", &menu);QAction *deleteAction = new QAction("刪除", &menu);connect(openAction, &QAction::triggered, [index, &model]() {QString path = model.filePath(index);QDesktopServices::openUrl(QUrl::fromLocalFile(path));});connect(deleteAction, &QAction::triggered, [index, &model]() {model.remove(index);});menu.addAction(openAction);menu.addAction(deleteAction);menu.exec(treeView.viewport()->mapToGlobal(pos));
}
五、繼承QFileSystemModel并進行自定義
繼承 QFileSystemModel 并進行自定義,可以用來修改文件顯示方式、攔截用戶操作、隱藏某些文件或添加額外的功能。
可以通過繼承 QFileSystemModel來:
- 自定義文件名顯示(如:在文件名前加上 [文件] 或 [目錄])。
- 自定義文件圖標。
- 隱藏某些文件/目錄。
- 攔截文件刪除或重命名操作。
示例 1:重寫 data() 修改文件顯示
默認情況下,QFileSystemModel 只顯示文件名。如果我們想要修改顯示內容(如:文件名前加上類型信息),可以重寫 data() 方法:
#include <QFileSystemModel>
#include <QDebug>class CustomFileSystemModel : public QFileSystemModel {
public:explicit CustomFileSystemModel(QObject *parent = nullptr) : QFileSystemModel(parent) {}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (!index.isValid()) return QVariant();if (role == Qt::DisplayRole) { // 修改顯示文本QString fileName = QFileSystemModel::data(index, Qt::DisplayRole).toString();if (isDir(index))return "[目錄] " + fileName;elsereturn "[文件] " + fileName;}return QFileSystemModel::data(index, role);}
};
示例 2:自定義文件圖標
如果想要為特定類型的文件設置不同的圖標(如 .txt 用文本圖標,.cpp 用代碼圖標),可以重寫 data() 的 Qt::DecorationRole:
#include <QFileIconProvider>
#include <QFileInfo>class CustomFileSystemModel : public QFileSystemModel {
public:explicit CustomFileSystemModel(QObject *parent = nullptr) : QFileSystemModel(parent) {}QVariant data(const QModelIndex &index, int role = Qt::DecorationRole) const override {if (!index.isValid()) return QVariant();if (role == Qt::DecorationRole) {QFileInfo fileInfo = this->fileInfo(index);if (fileInfo.suffix() == "txt")return QIcon(":/icons/text.png"); // 替換為你的圖標else if (fileInfo.suffix() == "cpp" || fileInfo.suffix() == "h")return QIcon(":/icons/code.png"); // 替換為你的圖標else if (fileInfo.isDir())return QIcon(":/icons/folder.png"); // 替換為你的文件夾圖標}return QFileSystemModel::data(index, role);}
};
示例 2:自定義雙擊打開文件
如果希望在雙擊文件時執行特定操作(如:打開文件或顯示信息),可以在 QTreeView 中監聽 doubleClicked() 信號:
QObject::connect(&treeView, &QTreeView::doubleClicked, [&](const QModelIndex &index) {QString filePath = model.filePath(index);if (model.isDir(index)) {qDebug() << "雙擊打開目錄:" << filePath;} else {qDebug() << "雙擊打開文件:" << filePath;QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));}
});
下面是一個完整的示例,將以上功能整合到 QTreeView 中:
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QMessageBox>
#include <QDesktopServices>
#include <QUrl>class CustomFileSystemModel : public QFileSystemModel {
public:explicit CustomFileSystemModel(QObject *parent = nullptr) : QFileSystemModel(parent) {}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (!index.isValid()) return QVariant();if (role == Qt::DisplayRole) {QString fileName = QFileSystemModel::data(index, Qt::DisplayRole).toString();return isDir(index) ? "[目錄] " + fileName : "[文件] " + fileName;}return QFileSystemModel::data(index, role);}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);CustomFileSystemModel model;model.setRootPath(QDir::homePath());QTreeView treeView;treeView.setModel(&model);treeView.setRootIndex(model.index(QDir::homePath()));QObject::connect(&treeView, &QTreeView::doubleClicked, [&](const QModelIndex &index) {QString filePath = model.filePath(index);QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));});treeView.resize(800, 600);treeView.show();return app.exec();
}