QTreeWidget实现一个打包小工具

不要低估你的能力,不要高估你的毅力。

前言

最近因为需要,着手写了个打包工具,功能挺简单的,目前就是基本的文件和文件夹复制。由于要求使用QT进行开发,个人又没有学过,因此完成下面的内容确实花了不少时间。由于网上的资源较少,而且达不到想要的效果,因此自己动手实现了许多功能,代码可能较为冗余(哭),好在功能实现了,多少有了点欣慰之感。

效果展示

首先,先给出几张效果展示图,目前没有任何美化,只是完成了功能,还有很大的改善空间。

1.运行截图为:

2.从上到下,分为三个板块,功能相同,具体演示为:

就是先打开一个文件夹,然后选择复制文件夹目录,选择复制即可。至于remove,可用于复制出错后删除相应文件,而generate按钮用于自动检索打开文件夹是否有批处理文件,有的话就执行。

这个小工具的难点在于文件夹的树形展示和对相应选中文件的操作。在开始制作时,首先是想在网上找找有没有相应的例子,但遗憾的是找到的都是相应用法(只是将项目通过QT展现出来),没有相关操作。QT好像也没有相应的函数,所以根据QT的QTreeWidget中自带的特性,东补西凑地完成了。

具体实现

这里主要采用了QTreeWidget,前期网上很多都是使用QtreeView,但QTreeView好像主要用于展示,对展示后的相关操作比较麻烦,而且效果不太好,于是转向了QTreeWidget。二者主要区别:

  • QTreeView一般和相应的QXXModel合用,形成Model/View结构.

  • QTreeWidget继承自QTreeView ,是封闭了默认Model的QTreeView,其中的元素是QTreeWidgetItem类型,要插入只需将新建QTreeWidgetItem的父类设为指定的QTreeWidget就行(在QTreeWidgetItem的构造函数中指定),要删除直接delete掉QTreeWidgetItem就行

两者的具体区别在此不多说,根据实际需要选择吧,这个小工具QTreeWidget比较适合,下面是实现源码。

实现源码

代码质量一般,其实相关功能的实现有多中方法,这里用的都是比较简单的,这里仅供参考。

在QT中新建一个widgets项目,命名为Robust,更改相应内容如下:

robust.h

#ifndef ROBUST_H
#define ROBUST_H

#include "subqtreewidgetitem.h"
#include "externarg.h"
#include <qmainwindow>
#include <qwidget>
#include <qmessagebox>
#include <qstring>
#include <qfilesystemmodel>
#include <qfiledialog>
#include <qlist>
#include <qfileinfolist>
#include <qtreewidget>
#include <qtreewidgetitem>
#include <qprocess>
#include <qdebug>

namespace Ui {
class Robust;
}

class Robust : public QMainWindow
{
    Q_OBJECT

public:
    explicit Robust(QWidget *parent = 0);
    QFileInfoList allfile(subQTreeWidgetItem *root,QString path);
    ~Robust();
    void copy(QString openPath, QString selectPath, QTreeWidget * treeWidget, QTreeWidget * toTreeWidget);
    bool copyFileToPath(QString sourceDir ,QString toDir, bool coverFileIfExist);
    bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist);
    QString treeItemToFullPath(QTreeWidgetItem* treeItem);
    void updateTreeWidgetShow(QString openPath, QTreeWidget * treeWidget);
    void updateTreeWidgetOpen(QString openPath, QTreeWidget * treeWidget);
    void remove(QString sourcePath, QTreeWidget *treeWidget);
    bool openFolder(QString openDir, QTreeWidget * treeWidget);
    bool generate(QString openPath,QTreeWidget * treeWidget);

private slots:
    void on_open_proj_clicked();
    void on_copy_button_clicked();
    void on_selectPath_clicked();
    void on_generate_clicked();
    void on_remove_clicked();
    void on_open_proj_2_clicked();
    void on_copy_2_clicked();
    void on_selectPath_2_clicked();
    void on_generate_2_clicked();
    void on_remove_2_clicked();
    void on_open_proj_3_clicked();
    void on_copy_3_clicked();
    void on_selectPath_3_clicked();
    void on_generate_3_clicked();
    void on_remove_3_clicked();

private:
    Ui::Robust *ui;
    QFileSystemModel *info;
};

#endif // ROBUST_H

externarg.h

#ifndef EXTERNARG
#define EXTERNARG

#endif // EXTERNARG
#include <qstring>
class ExternArg
{
public:
    ExternArg();
    //打开文件夹路径(不含文件夹名)
    static QString OPEN_PATH_1;
    //选择安装文件夹路径
    static QString SELECT_PATH_1;
    //打开文件件路径(包括文件夹名称)
    static QString OPEN_DIR_1;

    //打开文件夹路径(不含文件夹名)
    static QString OPEN_PATH_2;
    //选择安装文件夹路径
    static QString SELECT_PATH_2;
    //打开文件件路径(包括文件夹名称)
    static QString OPEN_DIR_2;

    //打开文件夹路径(不含文件夹名)
    static QString OPEN_PATH_3;
    //选择安装文件夹路径
    static QString SELECT_PATH_3;
    //打开文件件路径(包括文件夹名称)
    static QString OPEN_DIR_3;
};

subqtreewidgetitem.h

#ifndef SUBQTREEWIDGETITEM
#define SUBQTREEWIDGETITEM

#endif // SUBQTREEWIDGETITEM
#include <qtreewidgetitem>
#pragma once
class subQTreeWidgetItem : public QTreeWidgetItem
{

public:
    QString absPath;
    explicit subQTreeWidgetItem(const QStringList &strings, int type = Type);
    explicit subQTreeWidgetItem(QTreeWidget *view, int type = Type);
    subQTreeWidgetItem(QTreeWidget *view, const QStringList &strings, int type = Type);
};

robust.cpp

这里只留到第一部分的代码,第二三部分类似。

#include "robust.h"
#include "ui_robust.h"

Robust::Robust(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Robust)
{
    ui->setupUi(this);
}

Robust::~Robust()
{
    delete ui;
}


/************************************************  基本功能的实现  **************************************************************/


//打开文件夹,并以树形目录展示
bool Robust::openFolder(QString openDir, QTreeWidget * treeWidget)
{
    bool ok;
    if(QFile::exists(openDir))
    {
        treeWidget->clear();
        treeWidget->setHeaderLabel("project view");
        treeWidget->setSortingEnabled(true);
//        treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
        treeWidget->setSelectionMode(QAbstractItemView::MultiSelection);
        subQTreeWidgetItem* root = new subQTreeWidgetItem(treeWidget,QStringList()<<opendir); 设置一级目录展开="" qstringlist="" list="openDir.split("/");" int="" len="list.length();" root-="">setExpanded(true);
        root->setFirstColumnSpanned(true);
        root->setText(0,list.at(len-1));
        root->setIcon(0, QIcon(":/new/src/sourceFile/ico/proj.png"));
        root->setSelected(true);
        root->setCheckState(1, Qt::Checked);
        allfile(root,openDir);
        ok =true;
        return ok;
    }
    else
    {
        ok =false;
        return ok;
    }
}

//递归打开文件夹以树形结构显示的具体实现
QFileInfoList Robust::allfile(subQTreeWidgetItem *root,QString path)
{
    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();
        subQTreeWidgetItem* child = new subQTreeWidgetItem(QStringList()<<name2); child-="">setToolTip(0, path+"/"+name2);
        child->absPath = path+"/"+name2;
        child->setIcon(0, QIcon(":/new/src/sourceFile/ico/file_blue.png"));
        child->setCheckState(1, Qt::Checked);
        root->addChild(child);
    }
    QFileInfoList folder_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);   //获取当前所有目录
    QFileInfoList file_list=dir.entryInfoList(QDir::Files | QDir::Hidden | QDir::NoSymLinks);

    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();      //获取目录名
        subQTreeWidgetItem* childroot = new subQTreeWidgetItem(QStringList()<<name); childroot-="">setToolTip(0, path+"/"+name);
        childroot->absPath = path+"/"+name;
        childroot->setIcon(0, QIcon(":/new/src/sourceFile/ico/dir.png"));
        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;
}

//打开工程模块的显示更新
void Robust::updateTreeWidgetOpen(QString openPath, QTreeWidget * treeWidget)
{
    openFolder(openPath,treeWidget);
}

//递归获取所选文件或目录的相对路径,在这个基础上加上打开文件夹时的路径(没有文件夹名的路径),构成绝对路径。
QString Robust::treeItemToFullPath(QTreeWidgetItem* treeItem)
{
    QString fullPath= treeItem->text(0);
    while (treeItem->parent() != NULL)
    {
        fullPath= treeItem->parent()->text(0) + "/" + fullPath;
        treeItem = treeItem->parent();
    }
    return fullPath;
}

//文件和目录拷贝,这是为拷贝设置相应的路径和调用刷新treeWidget的内容显示。
void Robust::copy(QString openPath, QString selectPath, QTreeWidget * treeWidget, QTreeWidget * toTreeWidget)
{
    QList<qtreewidgetitem *=""> itemList;
    QString sourcePath;
    itemList = treeWidget->selectedItems();
    foreach(QTreeWidgetItem *item, itemList)
    {
        sourcePath = openPath + treeItemToFullPath(item);
//      QString sourcePath= openPath + treeItemToFullPath(treeWidget->selectedItems().first());
        QFileInfo *info;
        info = new QFileInfo(sourcePath);
        QString destPath;
        qDebug()<<"the source path:"<<sourcepath; if="" (qfile::exists(selectpath))="" {="" 复制到所选择的目录="" destpath="selectPath+"/"+info-">fileName();
            qDebug()<<"select path"<<destpath; }="" else="" {="" qmessagebox::information(this,tr("warning"),tr("need="" select="" path"));="" return;="" 如果目标路径包含原路径,则跳过,否则将递归进入死循环="" if(destpath.contains(sourcepath,="" qt::casesensitive)){="" qdebug()<<"contains";="" continue;="" if(!info-="">isDir()){
            qDebug()<<"destirtion path:"<<destpath; bool="" ok="copyFileToPath(sourcePath,destPath,true);" qdebug()<<"file:="" "<<ok;="" }="" else="" {="" qdebug()<<"destirtion="" path:"<<destpath;="" qdebug()<<"dir:="" updatetreewidgetshow(selectpath,="" totreewidget);="" 拷贝文件的具体实现="" robust::copyfiletopath(qstring="" sourcefile="" ,qstring="" tofile,="" coverfileifexist)="" tofile.replace("\\","="" ");="" if="" (sourcefile="=" tofile){="" return="" true;="" (!qfile::exists(sourcefile)){="" false;="" qdir="" *createfile="new" qdir;="" exist="createfile-">exists(toFile);
    if (exist){
        if(coverFileIfExist){
            createfile->remove(toFile);
        }
    }//end if

    if(!QFile::copy(sourceFile, toFile))
    {
        return false;
    }
    return true;
}

//拷贝文件夹的具体实现
bool Robust::copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
    QDir sourceDir(fromDir);
    QDir targetDir(toDir);
    if(!targetDir.exists()){   //如果目标目录不存在,则进行创建
        if(!targetDir.mkdir(targetDir.absolutePath()))
            return false;
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
            continue;

        if(fileInfo.isDir()){    //当为目录时,递归的进行copy
            if(!copyDirectoryFiles(fileInfo.filePath(),
                                   targetDir.filePath(fileInfo.fileName()),
                                   coverFileIfExist))
                return false;
        }
        else{            //当允许覆盖操作时,将旧文件进行删除操作
            if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
                targetDir.remove(fileInfo.fileName());
            }

            // 进行文件copy
            if(!QFile::copy(fileInfo.filePath(),
                            targetDir.filePath(fileInfo.fileName()))){
                return false;
            }
        }
    }
    return true;
}

//复制到所在目录的显示更新
void Robust::updateTreeWidgetShow(QString openPath, QTreeWidget * treeWidget)
{
    treeWidget->clear();
    QString aimPath;
    if (QFile::exists(openPath)){
        //复制到所选择的目录
        aimPath = openPath;
    }
    else
    {
        QMessageBox::information(this,tr("warning"),tr("need to select path"));
        return;
    }
    treeWidget->setHeaderLabel("the copy file");
    treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    treeWidget->setSortingEnabled(true);
    subQTreeWidgetItem* root1 = new subQTreeWidgetItem(treeWidget,QStringList()<<aimpath); 设置一级目录展开="" root1-="">setExpanded(true);
    root1->setFirstColumnSpanned(true);
    QStringList list1 = aimPath.split("/");
    int len1 = list1.length();
    root1->setText(0,list1.at(len1-1));
    root1->setIcon(0, QIcon(":/new/src/sourceFile/ico/proj.png"));
    root1->setSelected(true);
    root1->setCheckState(1, Qt::Checked);
    allfile(root1,aimPath);
}

//文件生成(编译)
bool Robust::generate(QString openPath,QTreeWidget * treeWidget)
{
    QDir dir(openPath);
    dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
    dir.setSorting(QDir::Size | QDir::Reversed);

    QFileInfoList list = dir.entryInfoList();
    for (int i = 0; i < list.size(); ++i) {
        QFileInfo fileInfo = list.at(i);
        if(fileInfo.suffix() == "bat")
        {
            QString filepath;
            filepath.append(fileInfo.path());
            qDebug()<<filepath; qprocess="" p(0);="" p.setworkingdirectory(filepath);="" 指定进程的工作目录="" filepath+="/" +fileinfo.filename();="" qdebug()<<filepath;="" qstring="" command="filepath;" p.start(command);="" p.waitforfinished();="" qdebug()<<"the="" result="" of="" exec="" bat:"<<qstring::fromlocal8bit(p.readallstandarderror());="" }="" updatetreewidgetopen(openpath,treewidget);="" return="" 1;="" 删除文件或文件夹="" void="" robust::remove(qstring="" selectpath,="" qtreewidget="" *treewidget)="" {="" int="" lastindex="selectPath.lastIndexOf("/")+1;" tempath="selectPath.mid(0,lastIndex)" +="" treeitemtofullpath(treewidget-="">selectedItems().first());
    qDebug()<<"the source path:"<<tempath; if(tempath="=" selectpath)="" {="" qmessagebox::information(this,tr("warning"),tr("can't="" remove="" the="" select="" dir"));="" return;="" }="" else="" qfileinfo="" *info;="" info="new" qfileinfo(tempath);="" if(info-="">isDir())
        {
            QDir tem = QDir(temPath);
            bool ok = tem.removeRecursively();
            qDebug()<<ok; }="" else="" {="" qfile="" *tem;="" tem="new" qfile(tempath);="" bool="" ok="tem-">remove();
            qDebug()<<ok; }="" updatetreewidgetshow(selectpath,="" treewidget);="" ************************************************="" 下面是各个模块的具体调用="" **************************************************************="" ********="" 第一板块的调用(treewidget_1和treewidget_2)="" ************="" 打开某个文件夹,并通过treewidget_1显示。="" void="" robust::on_open_proj_clicked()="" {="" externarg::open_dir_1="QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this," tr("view="" file"),="" qdir::currentpath()));="" qstring="" aimpath="ExternArg::OPEN_DIR_1.replace("\\","/");" qdebug()<<aimpath;="" qfileinfo="" *="" tem;="" tem="new" qfileinfo(aimpath);="" qdebug()<<"absolute="" path:="" "<<tem-="">absolutePath();
    //这里设置全局变量用于下面复制时的路径构造
    int i = tem->absolutePath().lastIndexOf("/");
    if(i == tem->absolutePath().length()-1)
    {
        ExternArg::OPEN_PATH_1 = tem->absolutePath();
    }
    else
    {
        ExternArg::OPEN_PATH_1 = tem->absolutePath()+"/";
    }
    qDebug()<<"ExternArg::OPEN_PATH"<<externarg::open_path_1; bool="" ok="openFolder(ExternArg::OPEN_DIR_1," ui-="">treeWidget_1);
    qDebug()<<ok; }="" 拷贝函数的调用="" void="" robust::on_copy_button_clicked()="" {="" copy(externarg::open_path_1,externarg::select_path_1,="" ui-="">treeWidget_1, ui->treeWidget_2);
}

//选择路径
void Robust::on_selectPath_clicked()
{
    QString path = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("view file"), QDir::currentPath()));
    ExternArg::SELECT_PATH_1 = path.replace("\\","/");
}

//编译调用
void Robust::on_generate_clicked()
{
    QString path = ExternArg::OPEN_DIR_1;
    bool ok = generate(path, ui->treeWidget_1);
    qDebug()<<ok; }="" 复制到所在文件夹的文件删除或文件夹删除="" void="" robust::on_remove_clicked()="" {="" qstring="" sourcepath="ExternArg::SELECT_PATH_1;" if(!qfile::exists(sourcepath))="" qmessagebox::information(this,tr("warning"),tr("need="" select="" path"));="" return;="" remove(sourcepath,ui-="">treeWidget_2);
}

externarg.cpp

#include "externarg.h"

ExternArg::ExternArg() {}

QString ExternArg::OPEN_PATH_1 = "";
QString ExternArg::SELECT_PATH_1 = "";
QString ExternArg::OPEN_DIR_1 = "";

QString ExternArg::OPEN_PATH_2 = "";
QString ExternArg::SELECT_PATH_2 = "";
QString ExternArg::OPEN_DIR_2 = "";

QString ExternArg::OPEN_PATH_3 = "";
QString ExternArg::SELECT_PATH_3 = "";
QString ExternArg::OPEN_DIR_3 = "";

subqtreewidgetitem.cpp

#include "subqtreewidgetitem.h"

subQTreeWidgetItem::subQTreeWidgetItem(const QStringList &strings1, int type1)
    :QTreeWidgetItem(strings1,type1)
{
    absPath = "";
}
subQTreeWidgetItem::subQTreeWidgetItem(QTreeWidget *view1, int type1)
    :QTreeWidgetItem(view1, type1)
{
    absPath = "";
}
subQTreeWidgetItem::subQTreeWidgetItem(QTreeWidget *view1, const QStringList &strings1, int type1)
    :QTreeWidgetItem(view1, strings1, type1)
{
    absPath = "";
}

main.cpp

#include "robust.h"
#include "subqtreewidgetitem.h"
#include <qapplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Robust w;
    w.show();

    return a.exec();
}
posted @ 2021-12-12 17:40  煊奕  阅读(209)  评论(0编辑  收藏  举报