不要低估你的能力,不要高估你的毅力。
前言
最近因为需要,着手写了个打包工具,功能挺简单的,目前就是基本的文件和文件夹复制。由于要求使用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();
}