大文件分割工具,QT实现

最近在学习QT开发,为了验证自己学习成果,最好还是做一个有点用的UI界面工具。想到了在前一家公司工作时,主要是分析出系统发生的异常,找出根本原因。这个异常可能发生在linux kernel,也可能是native 层的应用,也可能发生在apk中。特别是烧机和压力测试过程中发生的异常,通常会抓很多的log来辅助分析,这些log抓出来后会是一个好几G的大文件,利用文本工具打开来查看log,几G的文件基本打不开,就算可以打开,在里面搜索关键字也很慢,而且经常会卡死。所以就需要一个工具来把这几G的大文件分割成几个小一点的文件。从网上下载的一个工具,使用起来很麻烦,估计是在XP时代开发的,选择文件或者目录的时候,弹出来的是树状的文件结构,要不断展开,很不友好。所以我自己利用QT做了这样一个工具

大文件分割工具,QT实现_第1张图片

上面就是工具的界面,如果觉得不好看,可以下载源码自行修改

源码下载:https://download.csdn.net/download/xiongtiancheng/10424328

安装包下载:https://download.csdn.net/download/xiongtiancheng/10424352

安装包我是用Setup Factory 9 工具来打包的。

实现还算是比较简单了,主要是要理解QT中的布局管理,这样才能把组件放到理想的位置,显示合理的大小。下面是我认为一下值得分享的几个点,对刚接触QT的同学比较有用

1、添加图片资源

我们需要自定义按钮的样式,为了让按钮显示得好看些,需要使用到png图片

大文件分割工具,QT实现_第2张图片

在工程中点击右键,选择添加新文件,在弹出的新建文件窗口中选择Qt Resource File,然后点击选择

大文件分割工具,QT实现_第3张图片

在弹出的窗口中输入文件名,然后点击下一步,继续点击完成即可。

大文件分割工具,QT实现_第4张图片

然后会出现如上界面,点击添加下拉选择按钮,选择“添加前缀”

大文件分割工具,QT实现_第5张图片

然后随便输入一个前缀,比如/res ,然后继续点击添加下拉选择按钮,选择 “添加文件”

大文件分割工具,QT实现_第6张图片

在弹出的文件选择窗口中,选择要添加的png图片文件,或者其他文件,最后记得保存一下

引用对应的图片时,路径写成 :/res/xxx    例如

":/res/res/images/split_icon.png"

2、修改按钮样式

   QPushButton *btn_min = new QPushButton(centralWidget);
   btn_min->setFixedSize(40,30); //设置按钮大小
   btn_min->setFlat(true);    
   btn_min->setStyleSheet("QPushButton{background-image: url(:/res/res/images/min_normal.png);}"
              "QPushButton:hover{background-image: url(:/res/res/images/min_on.png);}"
              "QPushButton:pressed{background-image: url(:/res/res/images/min_press.png);}");

调用setStyleSheet() 就可以了,setFlat() 用来设置按钮扁平,不然看起来还是会凸起。


3、实现窗口移动

void MainWindow::mousePressEvent(QMouseEvent* e){  // 鼠标单击事件
    if(e->button()==Qt::LeftButton){
         mPressPos=e->pos();
         mPressed=true;
    }
}
void MainWindow::mouseMoveEvent(QMouseEvent* e){    // 鼠标移动事件
   if(mPressed){
       move(e->globalPos()-mPressPos);
   }
}
void MainWindow::mouseReleaseEvent(QMouseEvent* e){  // 鼠标释放事件
    mPressed=false;
}

这个很简单,重写mousePressEvent() , mouseMoveEvent() , mouseReleaseEvent() 这三个函数就可以了。

在mouseMoveEvent() 中调用move() 函数将窗口移动到需要的位置即可,move()中的参数是窗口的起始坐标(左上角),所以我们需要在按下时记录按下的点到窗口的起始点的位置mPressPos,e->globalPos()是相对于window桌面起始点的位置。e->globalPos()-mPressPos 正好得到窗口需要移动到的位置,这个位置是相对于桌面起始点的位置。


4、两个线程间传递消息

分割大文件无非是读取大文件的数据,然后写到几个小文件中,如果把读写文件的操作放在一个线程里面做,那么界面的更新就会卡住,鼠标移动到窗口上时会显示转圈圈,甚至会出现不响应的情况。所以我们需要把读写文件的操作放到另外一个线程中去做,当前的线程就负责更新界面显示。 那么读写文件的线程需要把更新界面的消息给到当前线程应该怎么实现呢?

 signals:
    void signalUpdate(int value);
    void signalAppend(const QString& appendText);

首先在读写文件的工作线程中定义signals 对应的函数,函数中的参数就是传给当前线程的参数。

protected slots:
    void onHandleUpdate(int value);
    void onHandleAppend(const QString& appendText);

在当前线程中定义 slots 对应的函数,函数的参数和signals 是对应的。

WorkerThread *workerThread = new WorkerThread(this);
      workerThread->setWorkerParams(filePath,dirPath,splitSize);
      connect(workerThread, SIGNAL(signalUpdate(int)), this, SLOT(onHandleUpdate(int)));
      connect(workerThread, SIGNAL(signalAppend(const QString&)), this, SLOT(onHandleAppend(const QString&)));
      // 线程结束后,自动销毁
      connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
      workerThread->start();

slots 和 signals 函数的绑定也是通过connect()来完成,和给按钮绑定点击事件类似。

signalUpdate(0);   //按钮无法点击

读写文件工作线程发送消息,调用signalUpdate() 实现。

void MainWindow::onHandleUpdate(int value){
     mProgressBar->setValue(value);
     if(value==0){
         mBtnStart->setEnabled(false);  //按钮无法点击
     }else if(value==100){
         mBtnStart->setEnabled(true); //按钮恢复可以点击
     }
}

当前的线程会收到消息,并回调onHandleUpdate() 函数处理。

这样的通信模型都很类似,无非是读写文件工作线程调用signalUpdate()后,会把要发送的消息打包成某种消息格式,然后放到当前线程的消息队列中,当前线程从消息队列中取出消息,解析消息,交给对应的处理函数处理。



你可能感兴趣的:(QT)