QDirModel

2018-10-07 15:20 更新

QDirModel

今天我們來看一個很有用的 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

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號