Qt线程任务实现拷贝文件功能

目标:

  1. 主窗口不能假死
  2. 主窗口进度条必须能动
  3. 改写文件大小的单位(自适应)
  4. 界面尽可能美观
  5. 添加暂停功能
  6. 要在窗口显示文件信息
界面样式:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QLocale>
#include <QDateTime>
#include <cmath>
#include "mythread.h"
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QString readPath;    // 保存文件读取地址
    QString writePath;    // 保存文件存储地址
    void printfFileInfo();    // 打印文件相关信息
    MyThread *ct=NULL;    // 线程
    void copy();    // 拷贝函数
private slots:
    void btnsClickedSlot();    // 按钮按下槽函数
    void valueSlot(int);    // 进度条设置
};

#endif // DIALOG_H

 dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    connect(ui->pushButtonOpen,SIGNAL(clicked()),    // 连接按钮
            this,SLOT(btnsClickedSlot()));    
    connect(ui->pushButtonSave,SIGNAL(clicked()),
            this,SLOT(btnsClickedSlot()));
    connect(ui->pushButtonCopy,SIGNAL(clicked()),
            this,SLOT(btnsClickedSlot()));
}

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

void Dialog::printfFileInfo()    // 打印文件信息函数
{
    QFileInfo info(readPath);    // 创建文件信息类info,可以通过其成员函数获得文件相关信息
    if(!info.exists())    // 存在为1,不存在为0,判断文件是否合法,不合法直接返回
    {
        return;
    }
    qint64 size = info.size();    // 获得文件大小,单位是字节
    float sizek = static_cast<float>(size);     // 数据类型转换
    QLocale locale;
    QString text;    // 存储要打印的文件信息
    if(size >= 1024 && size < pow(1024, 2))  // 文件大于1024,小于1024*1024字节,单位为MB
    {
        sizek = sizek / 1024;
        text = locale.toString(sizek, 'f', 2);    // 保留两位小数输出
        text.prepend("文件大小:").append("KB");
    }else if(size >= pow(1024,2) && size < pow(1024,3))
    {
        sizek = sizek / 1024 / 1024;
        text = locale.toString(sizek, 'f', 2);
        text.prepend("文件大小:").append("MB");
    }else if(size >=pow(1024,3) && size < pow(1024,4))
    {
        sizek = sizek / 1024 / 1024 / 1024;
        text = locale.toString(sizek, 'f', 2);
        text.prepend("文件大小:").append("GB");
    }else if(size < 1024)
    {
        text = QString::number(size);
        text.prepend("文件大小:").append("B");
    }
    ui->textBrowserOpen->append(text);

    text = info.baseName();    // 获得文件名字
    text.prepend("文件名字");  
    ui->textBrowserOpen->append(text);    // 在ui上显示
    // 获得最后修改时间
    text = info.lastModified().toString("修改时间:yyyy-MM-dd hh:mm:ss");    
    ui->textBrowserOpen->append(text);

    bool result = info.isReadable();    // 文件可读性
    if(result)
        ui->textBrowserOpen->append("文件可读");
    else
        ui->textBrowserOpen->append("文件不可读");

}

void Dialog::copy()    // 复制函数
{
    if(ui->pushButtonCopy->text() == "开始复制")    // 当按钮上显示“开始复制时”    
    {
        if(readPath == "")    // 没有选择文件打开时,跳出消息对话框进行提示
        {
            QMessageBox::warning(this,"提示","请选择要读取的文件!");
            return;
        }
        else if(writePath == "")    // 没有选择文件保存地址时,跳出提示
        {
            QMessageBox::warning(this,"提示","请选择要保存的文件地址!");
            return;
        }
        // 当下载进度为100%时,删除线程,为重新下载做准备
        if(ui->progressBar->value() == 100)    
        {
            ct = NULL;
        }
        if(ct == NULL)    // 当线程没有被创建时进入
        {
            // 创建子线程,在子线程中进行比较耗时的操作,即拷贝文件
            // 创建时将已打开的文件路径及要保存的文件路径传递过去
            ct = new MyThread(readPath,writePath,this);
            // 连接两个线程通信的信号槽,使progressBar->value的值能够实时更新
            connect(ct,SIGNAL(valueSignal(int)),this,SLOT(valueSlot(int)));
            // 设置run状态,开始复制
            ct->setRunningState(true);
            // 线程启动
            ct->start();
        }
        else    // 当线程已被创建时进入
        {
            ct->setRunningState(true);
        }

        ui->pushButtonCopy->setText("停止复制");    // 点击开始复制后,按钮变为停止复制
    }
    // 若按下时为停止复制(暂停)
    else if(ui->pushButtonCopy->text() == "停止复制")
    {
        ct->setRunningState(false);    // 停止复制
        ui->pushButtonCopy->setText("开始复制");    // 按钮变为开始复制
    }
}

void Dialog::btnsClickedSlot()    // 按钮点击槽函数
{
    if(ui->pushButtonOpen == sender())    // 如果点击的按钮是打开文件按钮
    {
        // 文件格式过滤器
        QString filter = "所有文件(*);;Qt(*.c *.cpp *.ui)";
        // 保存文件地址
        QString path = QFileDialog::getOpenFileName(this,"打开","D:/",filter);
        if(path != "")    // 选择文件后进入
        {
            ui->textBrowserOpen->append(path);    // 在窗口打印路径信息
            readPath = path;
            printfFileInfo();    // 调用打印信息函数

        }else if(readPath == "")    // 为选择文件进入
        {
            QMessageBox::warning(this,"注意","请选择要打开的文件");
        }
    }else if(ui->pushButtonSave == sender())    // 按下保存按钮时进入
    {
        QString filter = "所有文件(*);;Qt(*.c *.cpp *.ui)";
        QString path = QFileDialog::getSaveFileName(this,"保存","D:/",filter);
        if(path != "")
        {
            ui->textBrowserSave->append(path);
            writePath = path;

        }else if(writePath == "")
        {
            QMessageBox::warning(this,"注意","请选择要保存的地址");
            return;
        }
    }else if(ui->pushButtonCopy == sender())    // 按下复制按钮时进入,开始拷贝
    {
        copy();
    }
}

void Dialog::valueSlot(int value)    // 接受value值槽函数
{
    ui->progressBar->setValue(value);    // 设置value值
    if(value == 100)
    {
        // 释放按钮
        ui->pushButtonCopy->setEnabled(true);
        // 异步刷新
        this->hide();// 隐藏主窗口,只是看不到
        this->show();// 显示主窗口
        QMessageBox::information(this,"通知","文件拷贝完毕");
    }
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QFile>
#include <QDateTime>
class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QString,QString,QObject *parent = 0);     // 注意修改构造函数参数
    ~MyThread();

    bool getRunningState() const;
    void setRunningState(bool value);


signals:
    void valueSignal(int);
protected:
    void run();
private:
    bool runningState;
    QString readPath;
    QString writePath;
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
// 注意修改参数
MyThread::MyThread(QString readPath,QString writePath,QObject *parent) : QThread(parent)
{

    this->readPath = readPath;
    this->writePath = writePath;
}

MyThread::~MyThread()
{

}

void MyThread::run()
{
    // 创建QFile对象
    QFile readFile(readPath);
    QFile writeFile(writePath);

    // 打开文件流
    readFile.open(QIODevice::ReadOnly);
    writeFile.open(QIODevice::WriteOnly);

    // 获取文件总大小
    qint64 totalSize = readFile.size();
    // 已经读写的大小
    qint64 hasRead = 0;
    // 字节数组类
    QByteArray buffer;

    while(!readFile.atEnd()) // 判断是否位于文件尾部
    {
        // 当标志位为false时进入暂停延时,为true时跳出继续读写
        while(!runningState)    
        {
            msleep(100);
        }
        // 读取数据
        buffer = readFile.read(1024);
        // 写出数据
        hasRead += writeFile.write(buffer);
        // 算百分比
        int per = 100 * hasRead/totalSize;
        // 设置给进度条
        emit valueSignal(per);
    }

}
bool MyThread::getRunningState() const
{
    return runningState;
}

void MyThread::setRunningState(bool value)
{
    runningState = value;
}


  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值