文章目录
- 效果图
- 现实的功能
- 总体框架
- 功能介绍
- 视图
- 双击进入处理
- 复制与剪切
- 粘贴
- 重命名,新建
- 显示文件详细信息
- 文件路径导航栏
- 总结
效果图
现实的功能
- 支持文件/文件夹复制,粘贴,剪切,删除,重命名的基本操作
- 支持打开图片,文档等资源
- 支持文件显示详细信息
- 支持文件路径导航
- 支持文件拖入文件夹
总体框架
- 本案例主要使用了
QFileSystemModel
与QListView
。上方的路径导航栏使用了QListWidget
,每一个路径名为一个item
。关键在于你对QFileSystemModel
的使用。 - 下述代码可能已经更新,最新代码请到文末源码里拉取
功能介绍
视图
- 创建
QFileSystemModel
模型与QListView
视图,并设置相关参数,就可以显示本地的文件目录。关键在于要设置setViewMode
函数。
model = new QFileSystemModel(this);model->setRootPath(QDir::homePath());listView = new FileListView(this);listView->setModel(model);listView->setRootIndex(model->index(QDir::homePath()));listView->setDragEnabled(false);listView->setMovement(QListView::Static);listView->setViewMode(QListView::IconMode);listView->setResizeMode(QListView::Adjust);listView->setSpacing(20);listView->setIconSize(QSize(48, 48));listView->setGridSize(QSize(80, 80));listView->installEventFilter(this);
双击进入处理
- 在进入下一级的时候,要判断是文件还是文件夹,文件夹则进入,文件则调用系统默认的软件打开。
void FileExplorer::onDoubleClicked(const QModelIndex &index){ if (model->isDir(index)) { listView->setRootIndex(index); updatePath(index); } else { QString filePath = model->filePath(index); QDesktopServices::openUrl(QUrl::fromLocalFile(filePath)); }}
复制与剪切
- 复制与剪切的逻辑相似,需要维护一个保存要操作文件的路径,和判断是否为剪切的标志位。剪切就是使用复制,粘贴成功后删除原有的文件。
void FileExplorer::copyFileOrFolder(){ cutOperation = false; QModelIndexList indexes = listView->selectionModel()->selectedIndexes(); listOfFilesToCopy.clear(); for (QModelIndex index : indexes) { QString filePath = model->filePath(index); listOfFilesToCopy.append(filePath); } listView->clearSelection();}
粘贴
- 我们从复制/剪切下得到了需操作文件的路径,就可以使用
copy
函数实现粘贴,需要注意的是,要复制目录内容,需要递归地复制所有文件和子目录,若路径不存在则创建不存在的文件,不然无法复制粘贴成功,若是剪切,粘贴完后要删除原文件,并清空链表。
重命名,新建
显示文件详细信息
- 这个需要利用到事件过滤器,当判断到事件为
QEvent::ToolTip
时,使用QToolTip
显示得到的文件信息。
bool FileExplorer::eventFilter(QObject *watched, QEvent *event){ if (watched == listView && event->type() == QEvent::ToolTip) { QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event); if (helpEvent) { QModelIndex index = listView->indexAt(helpEvent->pos()); if (index.isValid()) { QString toolTipText; QLocale locale; QString filePath = model->filePath(index); QFileInfo fileInfo(filePath); QString longDate = locale.toString(fileInfo.lastModified(), QLocale::LongFormat); toolTipText = QString("Name: %1/nSize: %2KB/nType: %3/nLast Modified: %4") .arg(fileInfo.fileName()) .arg(!fileInfo.isFile() ? calculateFolderSize(filePath) : fileInfo.size() / 1024) .arg(!fileInfo.isFile() ? "file" : fileInfo.suffix()) .arg(longDate); QToolTip::showText(helpEvent->globalPos(), toolTipText); } else { QToolTip::hideText(); event->ignore(); } return true; } } return QWidget::eventFilter(watched, event);}
文件路径导航栏
- 主要思想就是使用
QListWidget
,每当路径变化时,就使用文件名重新生成item
,点击其中一个文件名时,就会拼接成正确的路径名从而实现跳转。
void FileListWidget::refresh(const QString &dir){ this->clear(); auto initlist = dir.split("/"); for (auto &str : initlist) { QListWidgetItem *item = new QListWidgetItem(str, this); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); addItem(">"); addItem(item); }}void FileExplorer::onitemClicked(QListWidgetItem *item){ if (!item) return; auto row = fileList->row(item) + 1; QString strdir; for (int i = 0; i < row; ++i) { QListWidgetItem *itemc = fileList->item(i); if (itemc->text() != ">") { strdir.push_back(QString(itemc->text() + "/")); } } strdir.chop(1); if (!strdir.isEmpty()) { fileList->refresh(strdir); model->setRootPath(strdir); listView->setRootIndex(model->index(strdir)); }}
总结
- 文件操作的功能基本实现,但还是存在一些BUG需要处理,有些功能可加入,待完善。
- 知识理应共享,源码在此(持续优化)。