QTC++搜索文件小应用制作日志(Gif演示)

2018/2/5的晚上,我想起来我舍友曾经买过一个可以自定义帮他寻找文件的小软件(当然还植入了可以再特定网页上也可以寻找)。他曾在我面前炫耀多次,作为一个精打细算的小屌丝,打算抽个空自己做一个简化版的这个东西。这大概就是要做这个东西的动机了。

目前最新版本的演示SearchShow.gif
  • 这个我称之为版本一。因为我打算只实现在特定的磁盘下搜索我想要的文件。

需求分析

  • 工具: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++)
方法很简单。

  1. 打开Qt的窗口版,就下面那个


    这个是windows下进行的开发哇!
  2. 用QTC++的IDE(Creater 来生成release版)


    很简单的啦
  3. 在文件夹中找到它


    这个很简单。一般你是会有两个向上面一样的文件夹(Debug就是默认的启动的版本)
    还有种就是release版。文件夹大致就是这个样子。

    在那个release的版本下找到release文件夹。
    那个exe

里面是有类似于一般的开发的原文件。我们这时,将这个exe文件放到外面的自己随便新建的文件夹下。
比如我,就把这个放到了外面的第一个文件夹下

第一个就是

  1. 还记得之前打开的那个黑框么?
    之前就先用 cd + 文件夹绝对路径 转到该路径下
    然后,输入命令windeployqt + XXX.exe (那个XXX是你的程序名字,具体可以看图)
    输入命令 windeployqt

然后在文件夹下,就会多出一堆文件来。


像这样

这时,只需要你点那个exe文件,就可以使用了。
温馨提示:要是出问题了,那就把那一堆,除了那个exe以外的都删掉。再来一次,这个还是很迷的....

  1. 将这个exe投影到桌面。
  • 右键它
  • 发送到
  • 找到桌面快捷键有关字样...

然后桌面上就多了这个玩意了。


像这样

平常点击下用就好了,然后需要改进的版本话,就可以等我的之后对这篇文章的不断更新。
记得点赞哦~那样以后就可以在简书``我喜欢过的文章`那找到这篇了

先这样

然后就这样

再点打开(没有后缀说明是文件夹,还有这是个下拉列表框)
点开就是这样

我试着点开了个Test.cpp来看


然后就是这样啦~会自动聚焦找到对应的地方的

我可以先把这个的mainwindow类函数给放出来。

2018/2/7 9:41分

完成了所有这样的类型搜索模式。整个系统的设计只剩下了最后一步,就是添加一个菜单栏,快捷键什么的。
此外,我发现如果显式的只是名字的话,会有很多情况自己都不知这个东西具体是什么,所以,我选择在这把显示的信息变成文件所在的绝对路径

  • 还存在可以优化的地方,我之前设置的容错次数是200次左右,就是说,连续搜索200次都没有遇到想要的东西,那就可以直接退出了。
  • 我现在设置的情况只能遍历D盘(因为我的电脑我只设置了一个D盘)


    2018/2/7
  • 如果对这个有开发兴趣的朋友们,我可以把这个放到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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,875评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,569评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,475评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,459评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,537评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,563评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,580评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,326评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,773评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,086评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,252评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,921评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,566评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,190评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,435评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,129评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,125评论 2 352

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,389评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,996评论 25 707
  • 不合时宜,这个概念当然范围很广,包括许多范畴——比如职场上,当众给领导提反对意见并且导致领导难堪,而且领导还是一个...
    锡安之光阅读 403评论 0 0
  • 女儿化学不好,要求去补习,于是我建议去找我同事的儿子先问问。他是各科成绩都很好,全年段排名前十名。女儿不知是...
    西畔阅读 156评论 0 0