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