#include <QApplication>

#include <QtWidgets>
#include <QtNetwork>

//downloads one file at a time, using a supplied QNetworkAccessManager object
class FileDownloader : public QObject{
    Q_OBJECT
public:
    explicit FileDownloader(QObject* parent= nullptr)
        :QObject(parent)
    {
        nam = new QNetworkAccessManager(this);
    }
    ~FileDownloader(){
        //destructor cancels the ongoing dowload (if any)
        if(networkReply){
            a_abortDownload();
        }
    }

    //call this function to start downloading a file from url to fileName
    void startDownload(QUrl url, QString fileName){
        if(networkReply) return;
        destinationFile.setFileName(fileName);
        if(!destinationFile.open(QIODevice::WriteOnly)) return;
        emit goingBusy();
        QNetworkRequest request(url);
        networkReply= nam->get(request);
        connect(networkReply, &QIODevice::readyRead, this, &FileDownloader::readData);
        connect(networkReply, &QNetworkReply::downloadProgress,
                this, &FileDownloader::downloadProgress);
        connect(networkReply, &QNetworkReply::finished,
                this, &FileDownloader::finishDownload);
    }

    //call this function to abort the ongoing download (if any)
    void abortDownload(){
        if(!networkReply) return;
        a_abortDownload();
        emit backReady();
    }

    //connect to the following signals to get information about the ongoing download
    Q_SIGNAL void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
    Q_SIGNAL void downloadSuccessful();
    Q_SIGNAL void downloadError(QString errorString);
    //the next two signals are used to indicate transitions between busy and
    //ready states of the file downloader, they can be used to update the GUI
    Q_SIGNAL void goingBusy();
    Q_SIGNAL void backReady();

private:
    Q_SLOT void readData(){
        QByteArray data= networkReply->readAll();
        destinationFile.write(data);
    }
    Q_SLOT void finishDownload(){
        if(networkReply->error() != QNetworkReply::NoError){
            //failed download
            a_abortDownload();
            qDebug() << "networkReply->errorString()"<<networkReply->errorString();
            emit downloadError(networkReply->errorString());
        } else {
            //successful download
            destinationFile.close();
            networkReply->deleteLater();
            qDebug() << "downloadSuccessful";
            emit downloadSuccessful();
        }
        emit backReady();
    }
    //private function, cleans things up when the download is aborted
    //(due to an error or user interaction)
    void a_abortDownload(){
        networkReply->abort();
        networkReply->deleteLater();
        destinationFile.close();
        destinationFile.remove();
    }

    QNetworkAccessManager* nam;
    QUrl downloadUrl;
    QFile destinationFile;
    QPointer<QNetworkReply> networkReply;
};

//A sample GUI application that uses the above class
class Widget : public QWidget{
    Q_OBJECT
public:
    explicit Widget(QWidget* parent= nullptr):QWidget(parent){
        layout.addWidget(&lineEditUrl, 0, 0);
        layout.addWidget(&buttonDownload, 0, 1);
        layout.addWidget(&progressBar, 1, 0);
        layout.addWidget(&buttonAbort, 1, 1);
        layout.addWidget(&labelStatus, 2, 0, 1, 2);
        lineEditUrl.setPlaceholderText("URL to download");
        connect(&fileDownloader, &FileDownloader::downloadSuccessful,
                this, &Widget::downloadFinished);
        connect(&fileDownloader, &FileDownloader::downloadError,
                this, &Widget::error);
        connect(&fileDownloader, &FileDownloader::downloadProgress,
                this, &Widget::updateProgress);
        connect(&buttonDownload, &QPushButton::clicked,
                this, &Widget::startDownload);
        connect(&buttonAbort, &QPushButton::clicked,
                this, &Widget::abortDownload);

        showReady();
        //use goingBusy() and backReady() from FileDownloader signals to update the GUI
        connect(&fileDownloader, &FileDownloader::goingBusy, this, &Widget::showBusy);
        connect(&fileDownloader, &FileDownloader::backReady, this, &Widget::showReady);
    }

    ~Widget() = default;

    Q_SLOT void startDownload(){
        if(lineEditUrl.text().isEmpty()){
            QMessageBox::critical(this, "Error", "Enter file Url", QMessageBox::Ok);
            return;
        }
        QString fileName =
                QFileDialog::getSaveFileName(this, "Destination File");
        if(fileName.isEmpty()) return;
        QUrl url= lineEditUrl.text();
        fileDownloader.startDownload(url, fileName);
    }
    Q_SLOT void abortDownload(){
        fileDownloader.abortDownload();
    }

    Q_SLOT void downloadFinished(){
        labelStatus.setText("Download finished successfully");
    }
    Q_SLOT void error(QString errorString){
        labelStatus.setText(errorString);
    }
    Q_SLOT void updateProgress(qint64 bytesReceived, qint64 bytesTotal){
        progressBar.setRange(0, bytesTotal);
        progressBar.setValue(bytesReceived);
    }
private:
    Q_SLOT void showBusy(){
        buttonDownload.setEnabled(false);
        lineEditUrl.setEnabled(false);
        buttonAbort.setEnabled(true);
        labelStatus.setText("Downloading. . .");
    }
    Q_SLOT void showReady(){
        buttonDownload.setEnabled(true);
        lineEditUrl.setEnabled(true);
        buttonAbort.setEnabled(false);
        progressBar.setRange(0,1);
        progressBar.setValue(0);
    }

    QGridLayout layout{this};
    QLineEdit lineEditUrl;
    QPushButton buttonDownload{"Start Download"};
    QProgressBar progressBar;
    QPushButton buttonAbort{"Abort Download"};
    QLabel labelStatus{"Idle"};
//    QNetworkAccessManager nam;
//    FileDownloader fileDownloader{&nam};
    FileDownloader fileDownloader;
};

int main(int argc, char* argv[]){
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

#include "main.moc"
												

封装qt http文件下载类的更多相关文章

  1. 用 Qt 的 QAudioOutput 类播放 WAV 音频文件

    用 Qt 的 QAudioOutput 类播放 WAV 音频文件 最近有一个项目,需要同时控制 4 个声卡播放不同的声音,声音文件很简单就是没有任何压缩的 wav 文件. 如果只是播放 wav 文件, ...

  2. Android RecyclerView单击、长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类

     Android RecyclerView单击.长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类 我写的附录文章2,介绍了 ...

  3. php 支持断点续传的文件下载类

    php 支持断点续传的文件下载类 分类: php class2013-06-30 17:27 17748人阅读 评论(6) 收藏 举报 php断点续传下载http测试 php 支持断点续传,主要依靠H ...

  4. Redis操作Hash工具类封装,Redis工具类封装

    Redis操作Hash工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>> ...

  5. Redis操作字符串工具类封装,Redis工具类封装

    Redis操作字符串工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>>& ...

  6. [上传下载] C#FileDown文件下载类 (转载)

    点击下载 FileDown.zip 主要功能如下 .参数为虚拟路径 .获取物理地址 .普通下载 .分块下载 .输出硬盘文件,提供下载 支持大文件.续传.速度限制.资源占用小 看下面代码吧 /// &l ...

  7. 【Android】19.3 ContentProvider及安卓进一步封装后的相关类

    分类:C#.Android.VS2015: 创建日期:2016-03-08 一.简介 ContentProvider:内容提供程序. Android的ContentProvider与.NET框架的EF ...

  8. Qt 的QString类的使用

    Qt的QString类提供了很方便的对字符串操作的接口. 使某个字符填满字符串,也就是说字符串里的所有字符都有等长度的ch来代替. QString::fill ( QChar ch, int size ...

  9. SpringMVC 中,当前台传入多个参数时,可将参数封装成一个bean类

    在实际业务场景中,当前台通过 url 向后台传送多个参数时,可以将参数封装成一个bean类,在bean类中对各个参数进行非空,默认值等的设置. 前台 url ,想后台传送两个参数,userName 和 ...

随机推荐

  1. 0001-代码仓库-git 命令

    参考 https://www.cnblogs.com/NTWang/p/6213408.html https://www.cnblogs.com/Sungeek/p/6905102.html

  2. 阿里云SOP

    阿里云SOP 摘要 注册阿里云账号. 领取及配置ECS. 领取及配置RDS. 部署网站. 注册阿里云账号 在主页点击注册 填入相应的信息 领取及配置ECS 注册后领取免费的ECS,RDS. 打开控制台 ...

  3. UIP和lwip的区别 转载

    uIP是专门为8位和16位控制器设计的一个非常小的TCP/IP栈.完全用C编写,因此可移植到各种不同的结构和操作系统上,一个编译过的栈可以在几KB ROM或几百字节RAM中运行.uIP中还包括一个HT ...

  4. 自定义Lombok注解

    Java 是一门"繁琐"的语言,使用 Lombok 可以显著地减少样板代码.比如使用 @Getter 注解可以为你的私有属性创建 get 方法. 源代码 @Getter priva ...

  5. k8s安装之nginx.yaml

    这里两个nginx.一个是用来测试最简单的集群的. 另一个是用来作grafana,prometheus,dashboard前端安全展示的. 简单版 apiVersion: apps/v1 kind: ...

  6. 帝国CMS熊掌号数据主动推送插件【原创】

    因为昨晚一个朋友他是帝国CMS做的网站,叫我给他做个熊掌号改造和熊掌号推送,所以花了一个小时时间做了这个插件,有需要的朋友可以拿去. 第一步:在后台执行以下数据库语句: CREATE TABLE `b ...

  7. 前端学习笔记--css案例

    要实现的案例: 1.分析布局 2.划分文件结构: 3.编写css代码 * { padding: 0; margin: 0; } body { font-size: 16px; color: burly ...

  8. Eclipse下,Maven+JRebel安装破解手记

    Java开发中,Maven已经是标配,使用JRebel能大大地提高工作效率,特别是在Web开发中,不用重启tomcat,大大地提高了工作效率. 1.前提条件 安装JDK 8 安装eclipse, ec ...

  9. python的拷贝方式以及深拷贝,浅拷贝详解

    python的拷贝方法有:切片方法, 工厂方法, 深拷贝方法, 浅拷贝方法等. 几种方法都可以实现拷贝操作, 具体区别在于两点:1.代码写法不同. 2.内存地址引用不同 代码演示: import co ...

  10. [GCP] Goolge compute Engine

    Which of the following is a PAAS option for hosting web apps on GCP? App Engine standard or flexible ...