QDir+QTreeWidget (QViewWidget) 展示文件系統樹形目錄


Qt包含一組項目視圖類,它們使用模型/視圖體系結構來管理數據之間的關系以及數據呈現給用戶的方式.

這里我們使用QStandardItemModel/QDirModel和 QTreeView或者 QTreeWidge來完成文件系統目錄的展示 。

1.  QStandardItemModel,功能強大,可先了解下。

QStandardItemModel q標准化模型類提供了一個用於存儲定制數據的通用模型。 q標准化模型可以作為標准Qt數據類型的存儲庫。它是模型/視圖類之一,也是Qt模型/視圖框架的一部分。 q標准化模型提供了一種經典的基於項目的方法來處理模型。q標准化模型提供了q標准化模型中的項目。 q標准化模型實現了QAbstractItemModel接口,這意味着該模型可以用於提供支持該接口的任何視圖中的數據(如QListView、QTableView和QTreeView,以及自定義的類型)。

當您需要一個列表或樹時,通常會創建一個空的q標准化模型,並使用appendRow()將項目添加到模型中,並使用item()來訪問項目。如果您的模型代表一個表,那么您通常將表的維度傳遞給q標准化模型構造函數,並使用setItem()將條目放置到表中。您還可以使用setRowCount()和setColumnCount()來改變模型的維度。要插入項,請使用insertRow()或insertColumn(),並刪除項目,使用removeRow()或removeColumn()。

 

QStandardItemModel:基於項數據的標准數據模型,可以處理二維數據。維護一個二維的項數據數組,每個項是一個 QStandardltem 類的變量,用於存儲項的數據、字體格式、對齊方式等。
QTableView:二維數據表視圖組件,有多個行和多個列,每個基本顯示單元是一個單元格,通過 setModel() 函數設置一個 QStandardItemModel 類的數據模型之后,一個單元格顯示 QStandardItemModel 數據模型中的一個項。
QItemSelectionModel:一個用於跟蹤視圖組件的單元格選擇狀態的類,當在 QTableView 選擇某個單元格,或多個單元格時,通過 QItemSelectionModel 可以獲得選中的單元格的模型索引,為單元格的選擇操作提供方便。

這幾個類之間的關系是:QTableView 是界面視圖組件,其關聯的數據模型是 QStandardItem Model,關聯的項選擇模型是 QItemSelectionModel,QStandardItemModel 的數據管理的基本單元是 QStandardItem。

QStandardItemModel繼承於QAbstractItemModel Class,用於存儲標准模型的數據

QTreeView繼承於QAbstractItemView Class,用於顯示樹視圖

當需要一個列表或樹時,通常會創建一個空的QStandardItemModel,並使用appendRow()將項添加到模型中,使用item()訪問一個項。

如果的模型表示一個表,那么通常會將表的維度傳遞給QStandardItemModel構造函數,並使用setItem()將項定位到表中。您還可以使用setRowCount()和setColumnCount()來更改模型的維度。要插入項目,使用insertRow()或insertColumn(),要刪除項目,使用removeRow()或removeColumn()。

如果模型表示一個樹,可以對模型(Model)使用appendRow()增加QStandardItem,對QStandardItem使用appendRow()增加QStandardItem(子節點)。其中,每個item的行號row均以上一節點(父節點)為基准:

 

2. QDirModel的使用
Qt上可以使用QFileSystemModel和QDirModel都可以獲得文件系統目錄結構數據。這里以QDirModel為例進行說明。

QDirModel類為本地文件系統提供了一個數據模型,顯示我們采用QTreeView。

按照系列教程(一)中對原理的講解,只要具備model和view,那么就可以進行顯示了。

核心代碼就三句話:

model = new QDirModel;
treeView = new QTreeView;
treeView->setModel(model);
創建一個model和view,再把model設置到view里面,view就可以顯示數據了。是不是很簡單。

3. QDirModel + QTreeView + QlineEdit 顯示絕對路徑

    model  = new QDirModel;
    model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);
    ui->treeView->header()->setStretchLastSection(true);
    ui->treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
    ui->treeView->header()->setSortIndicatorShown(true);
    //treeView->header()->setClickable(true);
    QModelIndex index = model->index("C:\Qt"/*QDir::currentPath()*/);
    ui-> treeView->expand(index);
    ui->treeView->scrollTo(index);
    ui->treeView->resizeColumnToContents(0);
    ui->treeView->setModel(model);
=========================================================================
    if(!connect(ui->treeView , SIGNAL(doubleClicked(QModelIndex)) , this , SLOT(treeViewSelect(const QModelIndex)))){
        qDebug("--error:4 teeView singal\n");
    }
void MainWindow::treeViewSelect(const QModelIndex& index)
{
      QString itemFullPath = model->filePath(index);
      QFileInfo fileInfo = model->fileInfo(index);
     //QStandardItem* item = QStandardItemModel::itemFromIndex(index);
      // QString itemFullPath = getItemFullPath(item);
       ui->lineEdit->setText(itemFullPath);
      qDebug()<<" parent : " <<itemFullPath;
}
 
         

========================================================================

 4. QDirModel + QTreeWidget + QlineEdit 顯示絕對路徑 

參考https://blog.csdn.net/houqd2012/article/details/21646121, 實現動態按需加載,能節省資源動態載入路徑。

    QTreeWidgetItem *top = new QTreeWidgetItem(ui->treeWidget , QStringList(QString(tr("我的電腦"))));
    top->setCheckState(1,Qt::Checked);
    root.append(top);
    ui->treeWidget->insertTopLevelItems(0 , root);


    //! 綁定掃DirScan掃描完的信號,發送過來添加進樹
    if(!connect(dirScan , SIGNAL(ItemScaned(QString,QFileInfo,int)) , this , SLOT(AddItem(QString,QFileInfo,int)))){
        qDebug("--error:1--\n");
    }

    //! 綁定本地樹控件的單擊事件,經過處理后發送出去,參數為點擊的path   //獲得path絕對路徑,轉換后,發送信號量到掃描類
    if(!connect(ui->treeWidget , SIGNAL(itemClicked(QTreeWidgetItem*,int)) , this , SLOT(selectItem(QTreeWidgetItem* , int)))){
        qDebug("--error:2--\n");
    }

    //! 綁定發送出去的事件,即發送給DirScan的事件
    if(!connect(this , SIGNAL(sendToDirScan(QString)) , dirScan , SLOT(Scan(QString)))){
        qDebug("--error:3--\n");
    }
    
void MainWindow::AddItem(const QString &strRootPath, const QFileInfo &ItemInfo , const int k)
{

    if(ItemInfo.isDir()){

        if(ItemInfo.fileName() == QLatin1String(".") || ItemInfo.fileName() == QLatin1String("..")){
            return ;
        }

        QString fullPath = ItemInfo.absolutePath().replace("/" , "\\") ;

//        if(!QString::compare(strRootPath , rootPath)){
//           return ;
//        }

        qDebug("(fullPath: %s)\n" , fullPath.toLatin1().data());

        // 這個只是第一次走,剩下的肯定都是包含的,因為盤符是在最外面的
        if(!m_StoreDirItem.contains(fullPath)){

            QString showname = ( k ? ItemInfo.fileName() : ItemInfo.filePath() );
            qDebug("---not----contains----k = %d ---------showname = %s.\n" , k , showname.toLatin1().data());
            QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget->findItems(QString(tr("我的電腦")) , 0 , 0).at(0) , QStringList(showname));

            m_StoreDirItem.insert(fullPath , item);

        }else{

            qDebug("---------contains---------\n");
            QTreeWidgetItem *item = m_StoreDirItem.value(fullPath);
            QTreeWidgetItem *item_1 = new QTreeWidgetItem(QStringList(ItemInfo.fileName()));

            int j ;
            for(j=0 ; j < item->childCount() ; j++){
                if(!QString::compare(ItemInfo.fileName() , item->child(j)->text(0))){
                    break ;
                }
            }

            if(j == item->childCount()){
                item->addChild(item_1);
                m_StoreDirItem.insert(ItemInfo.absoluteFilePath().replace("/","\\") , item_1);
            }
        }

    }else if(ItemInfo.isFile()){
        qDebug(":::::::I am a file.\n");

        QString fileFullPath = ItemInfo.filePath();
        QString filename = ItemInfo.fileName();

        QString file_path ;

        file_path = ItemInfo.absolutePath().replace("/","\\");

        qDebug("::::::file_path = %s\n" , file_path.toLatin1().data());

        if(!m_StoreDirItem.contains(file_path)){

            qDebug("----not contains----\n");
            QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget , QStringList(file_path));
            QTreeWidgetItem *item_1 = new QTreeWidgetItem(item , QStringList(filename));
            item->addChild(item_1);

            m_StoreDirItem.insert(file_path , item);
        }else{

            qDebug("---contains---\n");
            QTreeWidgetItem *item = m_StoreDirItem.value(file_path);
            QTreeWidgetItem *item_1 = new QTreeWidgetItem(QStringList(filename));
            int j ;
            for( j = 0 ; j < item->childCount() ; j++){
                if(!QString::compare(filename , item->child(j)->text(0))){
                    break ;
                }
            }

            qDebug("---j = %d and childCount = %d \n" , j , item->childCount());
            if(j == item->childCount()){
                item->addChild(item_1);
            }
        }
    }

   return ;

}

5.  以下是一個QDir + QFileinfoList 遍歷文件夾的實現,不知道QDirModel是否用類似方式來加載文件系統?

QFileInfoList MainWindow::allFile(QTreeWidgetItem *root,QString path)
{
    /*添加path路徑文件*/
    qDebug("first \n");
        QDir dir(path);          //遍歷各級子目錄
        QDir dir_file(path);    //遍歷子目錄中所有文件
        dir_file.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);        //獲取當前所有文件
        dir_file.setSorting(QDir::Size | QDir::Reversed);
        QFileInfoList list_file = dir_file.entryInfoList();
        for (int i = 0; i < list_file.size(); ++i) {       //將當前目錄中所有文件添加到treewidget中
            QFileInfo fileInfo = list_file.at(i);
            QString name2=fileInfo.fileName();
            QTreeWidgetItem* child = new QTreeWidgetItem(QStringList()<<name2);
            child->setIcon(0, QIcon(":/file/image/link.ico"));
            child->setCheckState(1, Qt::Checked);
            root->addChild(child);
        }
    qDebug("second \n");

        QFileInfoList file_list=dir.entryInfoList(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
        QFileInfoList folder_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);   //獲取當前所有目錄

        for(int i = 0; i != folder_list.size(); i++)         //自動遞歸添加各目錄到上一級目錄
        {

                 QString namepath = folder_list.at(i).absoluteFilePath();    //獲取路徑
                 QFileInfo folderinfo= folder_list.at(i);
                 QString name=folderinfo.fileName();      //獲取目錄名
                 QTreeWidgetItem* childroot = new QTreeWidgetItem(QStringList()<<name);
                 childroot->setIcon(0, QIcon(":/file/image/link.ico"));
                 childroot->setCheckState(1, Qt::Checked);
                 root->addChild(childroot);              //將當前目錄添加成path的子項
                 QFileInfoList child_file_list = allFile(childroot,namepath);          //進行遞歸
                 file_list.append(child_file_list);
                 file_list.append(name);
         }
        return file_list;

}

5.總結

Qt的模型/視圖功能很靈活,需要經常使用才能掌握其要領,這個練習只是第一步,需要更多的實戰來掌握其結構和使用方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM