#(34):QFileSystemModel
上一章我們詳細了解了`QStringListModel`。本章我們將再來介紹另外一個內置模型:`QFileSystemModel`。看起來,`QFileSystemModel`比`QStringListModel`要復雜得多;事實也是如此。但是,雖然功能強大,`QFileSystemModel`的使用還是簡單的。
讓我們從 Qt 內置的模型說起。實際上,Qt 內置了兩種模型:`QStandardItemModel`和`QFileSystemModel`。`QStandardItemModel`是一種多用途的模型,能夠讓列表、表格、樹等視圖顯示不同的數據結構。這種模型會將數據保存起來。試想一下,列表和表格所要求的數據結構肯定是不一樣的:前者是一維的,后者是二維的。因此,模型需要保存有實際數據,當視圖是列表時,以一維的形式提供數據;當視圖是表格時,以二維的形式提供數據。`QFileSystemModel`則是另外一種方式。它的作用是維護一個目錄的信息。因此,它不需要保存數據本身,而是保存這些在本地文件系統中的實際數據的一個索引。我們可以利用`QFileSystemModel`顯示文件系統的信息、甚至通過模型來修改文件系統。
`QTreeView`是最適合應用`QFileSystemModel`的視圖。下面我們看一段代碼:
~~~
FileSystemWidget::FileSystemWidget(QWidget *parent) :
QWidget(parent)
{
model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());
treeView = new QTreeView(this);
treeView->setModel(model);
treeView->setRootIndex(model->index(QDir::currentPath()));
QPushButton *mkdirButton = new QPushButton(tr("Make Directory..."), this);
QPushButton *rmButton = new QPushButton(tr("Remove"), this);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(mkdirButton);
buttonLayout->addWidget(rmButton);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(treeView);
layout->addLayout(buttonLayout);
setLayout(layout);
setWindowTitle("File System Model");
connect(mkdirButton, SIGNAL(clicked()),
this, SLOT(mkdir()));
connect(rmButton, SIGNAL(clicked()),
this, SLOT(rm()));
}
~~~
構造函數很簡單,我們首先創建了`QFileSystemModel`實例,然后將其作為一個`QTreeView`的模型。注意我們將`QFileSystemModel`的根目錄路徑設置為當前目錄。剩下來的都很簡單,我們添加了按鈕之類,這些都不再贅述。對于 treeView 視圖,我們使用了`setRootIndex()`對模型進行過濾。我們可以嘗試一下,去掉這一句的話,我們的程序會顯示整個文件系統的目錄;而這一句的作用是,從模型中找到?`QDir::currentPath()`所對應的索引,然后顯示這一位置。也就是說,這一語句的作用實際是設置顯示哪個目錄。我們會在后面的章節中詳細討論`index()`函數。
現在,我們可以運行以下程序看看界面:
[](http://files.devbean.net/images/2013/02/qfilesystemmodel-demo.png)
雖然我們基本一行代碼都沒寫(有關文件系統的代碼都沒有寫),但是從運行截圖可以看出,`QFileSystemModel`完全將所能想到的東西——名稱、大小、類型、修改時間等全部顯示出來,可見其強大之處。
下面是`mkdir()`槽函數:
~~~
void FileSystemWidget::mkdir()
{
QModelIndex index = treeView->currentIndex();
if (!index.isValid()) {
return;
}
QString dirName = QInputDialog::getText(this,
tr("Create Directory"),
tr("Directory name"));
if (!dirName.isEmpty()) {
if (!model->mkdir(index, dirName).isValid()) {
QMessageBox::information(this,
tr("Create Directory"),
tr("Failed to create the directory"));
}
}
}
~~~
正如代碼所示,首先我們獲取選擇的目錄。后面這個`isValid()`判斷很重要,因為默認情況下是沒有目錄被選擇的,此時路徑是非法的,為了避免程序出現異常,必須要有這一步判斷。然后彈出對話框詢問新的文件夾名字,如果創建失敗會有提示,否則就是創建成功。這時候你會發現,硬盤的實際位置的確創建了新的文件夾。
下面則是`rm()`槽函數:
~~~
void FileSystemWidget::rm()
{
QModelIndex index = treeView->currentIndex();
if (!index.isValid()) {
return;
}
bool ok;
if (model->fileInfo(index).isDir()) {
ok = model->rmdir(index);
} else {
ok = model->remove(index);
}
if (!ok) {
QMessageBox::information(this,
tr("Remove"),
tr("Failed to remove %1").arg(model->fileName(index)));
}
}
~~~
這里同樣需要先檢測路徑是否合法。另外需要注意的是,目錄和文件的刪除不是一個函數,需要調用`isDir()`函數檢測。這一步在代碼中有很清楚的描述,這里就不再贅述了。
實際上,我們這里不需要十分擔心`QFileSystemModel`的性能問題,因為它會啟動自己的線程進行文件夾掃描,不會發生因掃描文件夾而導致的主線程阻塞的現象。另外需要注意的是,`QFileSystemModel`會對模型的結果進行緩存,如果你要立即刷新結果,需要通知`QFileSystemWatcher`類。
如果仔細查看就會發現,我們的視圖不能排序不能點擊列頭。為此,我們可以使用下面代碼:
~~~
treeView->header()->setStretchLastSection(true);
treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
treeView->header()->setSortIndicatorShown(true);
#if QT_VERSION >= 0x050000
treeView->header()->setSectionsClickable(true);
#else
treeView->header()->setClickable(true);
#endif
~~~
這是 Qt 中視圖類常用的一種技術:如果我們要修改有關列頭、行頭之類的位置,我們需要從視圖類獲取到列頭對象,然后對其進行設置。正如代碼中所顯示的那樣。注意上面代碼片段的最后一部分,我們使用一個條件判斷來確定 Qt4 與 Qt5 的不同。
現在我們簡單介紹了有關兩個常用的模型類:QStringListModel 和 QFileSystemModel。下一章,我們將在此基礎上詳細介紹模型的相關細節。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)