2018/2/5的晚上,我想起来我舍友曾经买过一个可以自定义帮他寻找文件的小软件(当然还植入了可以再特定网页上也可以寻找)。他曾在我面前炫耀多次,作为一个精打细算的小屌丝,打算抽个空自己做一个简化版的这个东西。这大概就是要做这个东西的动机了。
- 这个我称之为版本一。因为我打算只实现在特定的磁盘下搜索我想要的文件。
需求分析
- 工具:QT C++(编译成一个小桌面应用)
- 搜索算法:广度优先搜索 + 贪心算法
- C++实现文件目录下的获取
- C++实现将搜索到的文件按照特定的顺序显式
- C++实现将设置PushButton可以添加指向到特定的文件管理器
2018/2/6
遇到了一个问题,在开发那个ScrollArea部分添加button的时候,发现,设置了search函数之后,添加不到button到右下角的灰色区域。
虽然一开始设置button的时候打算通过函数进行添加,但是在mainwindow类的构造函数中的设置,如果设置了多个button,后面出现的button就会将前面的button给覆盖掉。
上面的问题,我想了很多种方法还是完成不了,最终我选择了用一个ComoBox来代替,并添加一个打开的按钮在搜索旁边,这样,也就实现了对于整个东西的搜索,而且还是可以被打开的。(虽然看起来会比较简陋)
总的来说,对于这个项目还是有头绪的了。
那接下来的步骤就是
一、完成搜索
二、将搜索信息放到ComoBox中
三、点击Open打开文件管理器,并制定特殊文件路径
其中最难的应该就是第一步了,在设计的时候,通过C++实现对于文件夹的检索。
文件夹的检索
以前用Python做,这个就很简单了,但这次是为了锻炼C++水平,所以,努力用C++做出来。
第一步,获取D:/
下所有文件名字,并放到ComoBox中。
我们先用search做这一反映的借口。
其实先把在QtDesigner上将这个Search的button转成槽。接下来就慢慢实现。(最好再做一个函数,返回一个QStringList,这样我们之后就只需要去完善那个QStringList函数就好了)
在11:36分的时候实现了这个代码。
主要是实现起来实在是太简单了,放代码
QStringList MainWindow::Find(QString s){
QDir qdir;
qdir.setPath("D:/");
return qdir.entryList();
}
void MainWindow::on_SearchBTN_clicked()
{
QStringList sl = Find("D:/");
ui->comboBox->addItems(sl);
}
吃了个饭接着打代码
完成了一点小东西,下面这个代码可以完成在D:/
下第一级目录下的文件进行搜索。
找到特定的文件。
我在D:\
这个目录下建立了一个文件。叫肥宅.txt
下面我用这个不知道是几成品来搜索。
搜索很成功。距离成功又进了一步。
注释部分是我想要测试的一下用的东西。只在之前的基础上添加了这一个函数
QStringList MainWindow::Find(QString s){
QFileInfoList qfil= QDir("D:/").entryInfoList(QDir::Files);
QStringList qsl;
for (int i = 0; i < qfil.length(); ++i) {
if(qfil[i].baseName().contains(s)) {
// cout << qfil[i].isDir()<<endl;
// cout << (const char*)qfil[i].baseName().toLocal8Bit()<< endl;
qsl << qfil[i].baseName();
}
}
return qsl;
}
打了一小会代码,有意思
- 这次实现 广度优先搜索的效果。但是目前只能通过文件夹名字进行搜索。对了,我把我的很多软件都是装到
D:/
,而且我设置的目录都是以Sofeware
为文件名,而包括着。
所以在下面的代码中加入了这一个限制。这是因为在我不加的情况下,这个东西搜索要好久(而且特别占用空间,最后好像我检测到有20000+个文件夹在广搜的队列当中,不考虑减枝的话,我觉得这个还是比较麻烦的)
更新版代码Find函数
QStringList MainWindow::Find(QString s){
QStringList qsl; // file name
queue<QDir> q;
q.push(QDir("D:/"));
while(!q.empty()) {
QDir now = q.front();
cout << q.size()<< endl;
q.pop();
QFileInfoList qfil= now.entryInfoList(QDir::Files);
for(int i = 0; i < qfil.length(); ++i) {
if(qfil[i].baseName().contains(s, Qt::CaseInsensitive)) {
qsl << qfil[i].baseName();
urls << qfil[i].absoluteFilePath();
}
}
QFileInfoList qfilDir = now.entryInfoList(QDir::Dirs);
for(int i = 0; i < qfilDir.length(); ++i) {
if(qfilDir[i].baseName().contains(s, Qt::CaseInsensitive)) {
qsl << qfilDir[i].baseName(); // find the file then end search
urls << qfilDir[i].absoluteFilePath();
} else if (qfilDir[i].baseName().contains("software",Qt::CaseInsensitive)){
q.push(QDir(qfilDir[i].filePath()));
}
}
}
return qsl;
}
这次对Search
的槽函数也做了一个小修改了。
void MainWindow::on_SearchBTN_clicked()
{
ui->comboBox->clear(); // 将原来的进行清空。
QString name = ui->NameLET->text();
name = name.toLower();
QStringList sl = Find(name);
ui->comboBox->addItems(sl);
}
哈哈哈激动!终于完成了这样的一个初版(其实下午也就用在之前用的时间的基础上再用了半个小时)
- 先公布这个最简单的版本的代码和结构。下面,我们就开始将这个再编译一下,做一个简易版本的。桌面应用。
- 我就只展示mainwindow类的实现,外加上main函数。此外,就只有一个ui文件了,但是那个文件,我是用Qt designer手动拖的。你们也可以这么来做。(大概做我之前的那个样子也就可以了。(至于对应的控件名,我还是加下备注))
本来以为自己都做好了,做了几次测试之后,发现文件中有.
,..
也被考虑了进来,结果很多文件都是重复考虑了,结果浪费了大量的时间,那这样,还不如我自己手动找文件呢!
- 这个问题很简单就解决了。
QDir::NoDotAndDotDot
我加了这个参数,进行筛选,就避免了这个问题。
此外,还遇到了一个问题,就是我一点开就把那个可执行的文件给直接打开了....虽然如果这个是文件夹的时候没有问题,但要是不是的话....那就GG了
- 我给了这个问题的第一个解决方法:
如果是文件,就特定地将对应的url变成这个文件所在的文件夹
代码:qfil[i].dir().absolutePath();
其中qfil[i]的类型是QFileInfo。
但是遇到了这样会把打开所在文件夹,但是确实会把整个东西搞的乱乱的。比如:这个文件夹下内容很多的时候,我这样只把文件夹给打开,我也找不到时在哪???那搞什么搞?
- 20:53分,洗完澡后,解决了这个问题。
换用,调用进程的方式,调用一个分离的进程,然后,使用命令行来进行处理。
命令代码:QString("explorer.exe /select, ")+url
特别要注意那个/select
后面有一个逗号,
这样,我们的初版就算是做好了!
21:03还剩余的工作:
- 关于对于文件类型的筛选
- 关于两者结合的筛选
- 暂时就想到这么多。剩下的我们慢慢来。(对了,我现在其实只用了广度搜索,贪心算法还没有用)
补充一点
为了避免用时过多,我设计了一旦搜索不到的次数超过200次的时候,就直接break掉。
然后生成桌面应用
虽然按理说直接将对应的exe文件,发送一个快捷键到桌面上就好了的,但是为了学习和总结QT C++开发的过程,我们这,先使用的方法是,编译生成一个可以打包的文件,这样就算是别人想要下载下来使用也是可以的。(没有装C++)
方法很简单。
-
打开Qt的窗口版,就下面那个
-
用QTC++的IDE(Creater 来生成release版)
-
在文件夹中找到它
这个很简单。一般你是会有两个向上面一样的文件夹(Debug就是默认的启动的版本)
还有种就是release版。文件夹大致就是这个样子。
在那个release的版本下找到release
文件夹。
里面是有类似于一般的开发的原文件。我们这时,将这个exe文件放到外面的自己随便新建的
文件夹下。
比如我,就把这个放到了外面的第一个文件夹下
- 还记得之前打开的那个黑框么?
之前就先用cd
+文件夹绝对路径
转到该路径下
然后,输入命令windeployqt
+XXX.exe
(那个XXX是你的程序名字,具体可以看图)
然后在文件夹下,就会多出一堆文件来。
这时,只需要你点那个exe文件,就可以使用了。
温馨提示:要是出问题了,那就把那一堆,除了那个exe以外的都删掉。再来一次,这个还是很迷的....
- 将这个exe投影到桌面。
- 右键它
- 选
发送到
- 找到
桌面快捷键
有关字样...
然后桌面上就多了这个玩意了。
平常点击下用就好了,然后需要改进的版本话,就可以等我的之后对这篇文章的不断更新。
记得点赞哦~那样以后就可以在简书``我喜欢过的文章`那找到这篇了
再点打开(没有后缀说明是文件夹,还有这是个下拉列表框)
我试着点开了个Test.cpp来看
我可以先把这个的mainwindow类函数给放出来。
2018/2/7 9:41分
完成了所有这样的类型搜索模式。整个系统的设计只剩下了最后一步,就是添加一个菜单栏,快捷键什么的。
此外,我发现如果显式的只是名字的话,会有很多情况自己都不知这个东西具体是什么,所以,我选择在这把显示的信息变成文件所在的绝对路径
- 还存在可以优化的地方,我之前设置的容错次数是200次左右,就是说,连续搜索200次都没有遇到想要的东西,那就可以直接退出了。
我现在设置的情况只能遍历D盘(因为我的电脑我只设置了一个D盘)
- 如果对这个有开发兴趣的朋友们,我可以把这个放到github上,一起研究。(有,可以私戳我~,评论也行)
代码在此!(这是很老以前的版本,新版代码太长了,就放在github上了,大家有兴趣可以去做一个新的分支,大家一起改改~)
github链接为:
https://github.com/Sean16SYSU/QtProject.git
.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDir>
#include <QMainWindow>
#include <queue>
#include <QProcess>
#include <QDesktopServices>
#include <QUrl>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_SearchBTN_clicked();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
void addBTN(QString Message, int minWidth=360);
QStringList Find(QString s);
QStringList urls;
void Open(QString url);
bool CanUse(QString);
QStringList cannotuse;
int MAXLEN;
};
#endif // MAINWINDOW_H
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setMaximumSize(699, 351);
this->setMinimumSize(699, 351);
cannotuse << "software"<< "tim"<<"."<<"..";
MAXLEN = 200;
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::CanUse(QString s){
for (int i=0; i < cannotuse.length(); ++i) {
if (s.contains(cannotuse[i],Qt::CaseInsensitive)){
return false;
}
}
return true;
}
QStringList MainWindow::Find(QString s, int mode){
QStringList qsl; // file name
queue<QDir> q;
q.push(QDir("D:/"));
int count = 0; // mode = 0 name, mode = 1 suffix, mode = 2 full
while(!q.empty()) {
count += 1;
QDir now = q.front();
if (count > MAXLEN) break;
q.pop();
QFileInfoList qfil= now.entryInfoList(QDir::Files);
for(int i = 0; i < qfil.length(); ++i) {
if (mode == 0) {
if(qfil[i].baseName().contains(s, Qt::CaseInsensitive)) {
qsl << qfil[i].absoluteFilePath();
urls << qfil[i].absoluteFilePath();
count = 1;
}
} else if(mode == 1) {
if (qfil[i].suffix() == s) {
qsl << qfil[i].absoluteFilePath();
urls << qfil[i].absoluteFilePath();
count = 1;
}
} else if (qfil[i].fileName() == s) {
qsl << qfil[i].absoluteFilePath();
urls << qfil[i].absoluteFilePath();
count = 1;
}
}
QFileInfoList qfilDir = now.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
for(int i = 0; i < qfilDir.length(); ++i) {
if(mode == 0){
if(qfilDir[i].baseName().contains(s, Qt::CaseInsensitive)) {
qsl << qfilDir[i].absoluteFilePath(); // find the file then end search
urls << qfilDir[i].absoluteFilePath();
} else if (CanUse(qfilDir[i].baseName())){
q.push(QDir(qfilDir[i].filePath()));
}
} else if (CanUse(qfilDir[i].baseName())){
q.push(QDir(qfilDir[i].filePath()));
}
}
}
return qsl;
}
void MainWindow::on_SearchBTN_clicked()
{
ui->comboBox->clear();
urls.clear();
QString name = ui->NameLET->text();
QString type = ui->TypeLET->text();
type = type.toLower();
name = name.toLower();
type = type.trimmed();
name = name.trimmed();
if (name.length() == 0 && type.length() == 0) return;
QString target = name;
int mode = 0;
if (name.length() == 0 && type.length() != 0) {
mode = 1;
target = type;
} else if(name.length() != 0 && type.length() != 0) {
mode = 2;
target = target + "." + type;
}
QStringList sl = Find(target, mode);
ui->comboBox->addItems(sl);
}
void MainWindow::Open(QString url){
url.replace("/", "\\");
QProcess process;
process.startDetached(QString("explorer.exe /select, ")+url);
}
void MainWindow::on_pushButton_clicked()
{
if (ui->comboBox->count()){
int index = ui->comboBox->currentIndex();
Open(urls[index]);
}
}
```![![![SearchShow.gif](http://upload-images.jianshu.io/upload_images/8529255-a089fa4f2af417ae.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](http://upload-images.jianshu.io/upload_images/8529255-2365065252ba6546.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](http://upload-images.jianshu.io/upload_images/8529255-672c9657f4f782af.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)