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