QT使用QFileSystemModel实现的文件资源管理器(开源)

开源 0

文章目录

      • 效果图
      • 现实的功能
      • 总体框架
      • 功能介绍
        • 视图
        • 双击进入处理
        • 复制与剪切
        • 粘贴
        • 重命名,新建
        • 显示文件详细信息
        • 文件路径导航栏
      • 总结

效果图

在这里插入图片描述

现实的功能

  1. 支持文件/文件夹复制,粘贴,剪切,删除,重命名的基本操作
  2. 支持打开图片,文档等资源
  3. 支持文件显示详细信息
  4. 支持文件路径导航
  5. 支持文件拖入文件夹

总体框架

  • 本案例主要使用了QFileSystemModelQListView。上方的路径导航栏使用了QListWidget,每一个路径名为一个item。关键在于你对QFileSystemModel 的使用。
  • 下述代码可能已经更新,最新代码请到文末源码里拉取

功能介绍

视图
  • 创建QFileSystemModel 模型与QListView视图,并设置相关参数,就可以显示本地的文件目录。关键在于要设置setViewMode函数。
// 创建文件系统模型model = new QFileSystemModel(this);model->setRootPath(QDir::homePath());// 创建ListView并设置其模型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){    // 验证事件是针对 listView 的    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需要处理,有些功能可加入,待完善。
  • 知识理应共享,源码在此(持续优化)。

也许您对下面的内容还感兴趣: