今天我們來看一個很有用的 model:QDirModel。這個 model 允許我們在 view 中顯示操作系統(tǒng)的目錄結(jié)構(gòu)。這次讓我們先來看看運行結(jié)果:
這個界面很熟悉吧?不過這可不是由 QFileDialog 打開的哦,這是我們自己實現(xiàn)的。而提供這種實現(xiàn)支持的,就是 QDirModel 和 QTreeView。我們來看一下代碼。
mytreeview.h
#ifndef MYLISTVIEW_H
#define MYLISTVIEW_H
#include <QtGui>
class MyTreeView : public QWidget
{
Q_OBJECT
public:
MyTreeView();
private:
QDirModel *model;
QTreeView *treeView;
private slots:
void mkdir();
void rm();
};
#endif // MYLISTVIEW_H
mytreeview.cpp
#include "mylistview.h"
MyTreeView::MyTreeView()
{
model = new QDirModel;
model->setReadOnly(false);
model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);
treeView = new QTreeView;
treeView->setModel(model);
treeView->header()->setStretchLastSection(true);
treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
treeView->header()->setSortIndicatorShown(true);
treeView->header()->setClickable(true);
QModelIndex index = model->index(QDir::currentPath());
treeView->expand(index);
treeView->scrollTo(index);
treeView->resizeColumnToContents(0);
QHBoxLayout *btnLayout = new QHBoxLayout;
QPushButton *createBtn = new QPushButton(tr("Create Directory..."));
QPushButton *delBtn = new QPushButton(tr("Remove"));
btnLayout->addWidget(createBtn);
btnLayout->addWidget(delBtn);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(treeView);
mainLayout->addLayout(btnLayout);
this->setLayout(mainLayout);
connect(createBtn, SIGNAL(clicked()), this, SLOT(mkdir()));
connect(delBtn, SIGNAL(clicked()), this, SLOT(rm()));
}
void MyTreeView::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"));
}
}
}
void MyTreeView::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)));
}
}
構(gòu)造函數(shù)中,首先我們創(chuàng)建了 QDirModel 的一個對象,并且設(shè)置 ReadOnly 為 false,也就是說我們可以對其進行修改。而下一個 setSorting()函數(shù)是對其進行排序,排序的依據(jù)也很清楚:文件夾優(yōu)先(QDir::DirsFirst),忽略大小寫(QDir::IgnoreCase),而且是根據(jù)名字排序(QDir::Name)。更多的規(guī)則組合可以參見 API 文檔了。
然后我們創(chuàng)建一個 QTreeView 實例,并且把 model 設(shè)置為剛剛的 QDirModel 實例。然后我們開始設(shè)置 QTreeView 的相關(guān)屬性。首先把 stretchLastSection 設(shè)置為 true。如果把這個屬性設(shè)置為true,就是說,當 QTreeView 的寬度大于所有列寬之和時,最后一列的寬度自動擴展以充滿最后的邊界;否則就讓最后一列的寬度保持原始大小。第二個 setSortIndicator()函數(shù)是設(shè)置哪一列進行排序。由于我們前面設(shè)置了 model 是按照名字排序,所以我們這個傳遞的第一個參數(shù)是0,也就是第1列。setSortIndicatorShown()函數(shù)設(shè)置顯示列頭上面的排序小箭頭。setClickable(true)則允許鼠標點擊列頭。這樣,我們的 QTreeView 就設(shè)置完畢了。最后,我們通過 QDir::currentPath()獲取當前 exe 文件運行時路徑,并把這個路徑當成程序啟動時顯示的路徑。expand()函數(shù)即展開這一路徑;scrollTo()函數(shù)是把視圖的視口滾動到這個路徑的位置;resizeColumnToContents()是要求把列頭適應內(nèi)容的寬度,也就是不產(chǎn)生...符號。這樣,我們就通過一系列的參數(shù)設(shè)置好了 QTreeView,讓它能夠為我們展示目錄結(jié)構(gòu)。
至于后面的兩個 slot,其實并不能理解。第一個 mkdir()函數(shù)就是創(chuàng)建一個文件夾。
void MyTreeView::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()的判斷很重要,因為默認情況下是沒有目錄被選擇的,此時這個路徑是非法的,為了避免程序出現(xiàn)異常,必須要有這一步判斷。然后會彈出對話框詢問新的文件夾名字,如果創(chuàng)建失敗會有提示,否則就是創(chuàng)建成功。這時候你就可以到硬盤上的實際位置看看啦!
刪除目錄的代碼也很類似:
void MyTreeView::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)));
}
}
同樣需要實現(xiàn)檢測路徑是否合法。另外需要注意的是,目錄和文件的刪除不是一個函數(shù),需要調(diào)用 isDir()函數(shù)檢測。這一步在代碼中有很清楚的描述,這里就不再贅述了。
注意,QDirModel 在最新版 Qt 中已經(jīng)不建議使用了。文檔中說使用 QFileSystemModel 代替。由于這兩者的函數(shù)幾乎一樣,所以就沒有對代碼進行修改。與QDirModel 不同的是,QFileSystemModel會啟動自己的線程進行文件夾的掃描,因此不會發(fā)生因掃描文件夾而導致的主線程阻塞的現(xiàn)象。另外,無論 QDirModel 還是 QFileSystemModel 都會對 model 結(jié)果進行緩存,如果你要立即刷新結(jié)果,前者提供了 refresh()函數(shù),而后者會通知 QFileSystemWatcher 類。
本文出自 “豆子空間” 博客,請務必保留此出處 http://devbean.blog.51cto.com/448512/193918
更多建議: