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的模型/视图功能很灵活,需要经常使用才能掌握其要领,这个练习只是第一步,需要更多的实战来掌握其结构和使用方式。

posted @ 2020-09-23 16:22  七星望  阅读(3552)  评论(0编辑  收藏  举报