Qt之HTTP模仿迅雷——根据URL获取文件信息(下)

一、简述

在上篇 Qt 之 模仿迅雷 根据Url获取文件信息——上 文章中简单介绍了一下几个版本迅雷的界面变化,同时展示了这两天模仿迅雷新建任务窗口做的一个小例子。在这一篇中将讲解如何实现迅雷新建任务窗口

首先简单看一下效果图。

这里写图片描述

二、代码之路

看代码之前需要看一下Qt 之 自定义窗口标题栏这一篇文章,因为这里用到了这篇文章中写到的自定义标题栏。

这里新建任务窗口类NewTaskWindow 继承了BaseWindow类,所以省去了一些代码实现(主要包括顶部标题栏、鼠标按住标题栏进行拖动,窗口背景色等 ),有需要的小伙伴可以去看一下这一篇文章。

newtaskwindow.h

#include <QWidget>
#include "ui_newtaskwindow.h"
#include "basewindow.h"

class NewTaskWindow : public BaseWindow
{
    Q_OBJECT

public:
    NewTaskWindow(QWidget *parent = 0);
    ~NewTaskWindow();

private:
    void initWindow();
    void initTitleBar();
    void initTableWidget();
    void initFilePathLineEdit();
    QString getDiskFreeSpace(QString filePath);
    void setFileInfo(QString fileName, QString fileType, QString fileSize);
    void showFileInfo(QString fileName , QString fileSize);
    void hideFileInfo();
    void getFileTotalSize(QString url, int tryTimes = 1);
    QString transformUnit(double bytes);

    void paintEvent(QPaintEvent *event);

private slots:
    void onTextChanged();
    void onOpenFolder();

private:
    Ui::NewTaskWindow ui;
    QString m_filePath;
    QLabel* m_remainSpaceLabel;
};

newtaskwindow.cpp

#include "newtaskwindow.h"
#include <QPainter>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QFileInfo>
#include <QFileDialog>
#include "windows.h"

//http://down10.zol.com.cn/fanyi/Youdao701111.zip

#define UNIT_KB 1024            //KB
#define UNIT_MB 1024*1024       //MB
#define UNIT_GB 1024*1024*1024  //GB

NewTaskWindow::NewTaskWindow(QWidget *parent)
    : BaseWindow(parent)
    , m_filePath("D:/")
{
    ui.setupUi(this);
    initWindow();
}

NewTaskWindow::~NewTaskWindow()
{

}

void NewTaskWindow::initWindow()
{
    // 初始化标题栏;
    initTitleBar();
    // 初始化文件信息表格;
    initTableWidget();
    // 初始化路径栏目;
    initFilePathLineEdit();
    // 加载样式表;
    loadStyleSheet("NewTaskWindow");
    connect(ui.pButtonOpenFolder, SIGNAL(clicked()), this, SLOT(onOpenFolder()));
    connect(ui.textEdit, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
}

// 初始化标题栏;
void NewTaskWindow::initTitleBar()
{
    m_titleBar->move(0, 3);
    m_titleBar->setBackgroundColor(255, 255, 255);
    m_titleBar->setTitleContent(QStringLiteral("新建任务"));
    m_titleBar->setButtonType(ONLY_CLOSE_BUTTON);
    m_titleBar->setTitleWidth(this->width());
}

// 初始化文件信息表格栏目;
void NewTaskWindow::initTableWidget()
{
    ui.textEdit->setPlaceholderText(QStringLiteral("添加多个下载链接时,请确保每行只有一个链接。"));
    ui.tableWidget->setSortingEnabled(false);                               // 设置不可排序;
    ui.tableWidget->setFrameShape(QFrame::NoFrame);                         // 设置无边框;
    ui.tableWidget->setShowGrid(false);                                     // 设置不显示格子线;
    ui.tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);  // 设置标题垂直居中,水平居左;
    ui.tableWidget->horizontalHeader()->setHighlightSections(false);
    ui.tableWidget->horizontalHeader()->resizeSection(0, 215);
    ui.tableWidget->horizontalHeader()->resizeSection(1, 58);
    ui.tableWidget->horizontalHeader()->resizeSection(2, 79);

    // 隐藏文件信息表格栏目;
    hideFileInfo();
}

// 初始化路径栏目;
void NewTaskWindow::initFilePathLineEdit()
{
    // 内嵌QLabel 显示剩余空间;
    m_remainSpaceLabel = new QLabel;
    QString reaminSpace = QStringLiteral("剩余:%1").arg(getDiskFreeSpace(m_filePath));
    m_remainSpaceLabel->setText(reaminSpace);
    m_remainSpaceLabel->setStyleSheet("color:rgb(25, 125, 203);font-size:12px;");

    QHBoxLayout* filePathLayout = new QHBoxLayout;
    filePathLayout->addStretch();
    filePathLayout->addWidget(m_remainSpaceLabel);
    filePathLayout->setSpacing(0);
    filePathLayout->setContentsMargins(0, 0, 10, 0);

    ui.lineEdit->setLayout(filePathLayout);
    ui.lineEdit->setTextMargins(6, 0, 90, 0);
    ui.lineEdit->setText(m_filePath);

}

// 根据路径返回磁盘剩余控件大小;
QString NewTaskWindow::getDiskFreeSpace(QString filePath)
{
    LPCWSTR lpcwstrDriver = (LPCWSTR)filePath.utf16();

    ULARGE_INTEGER liFreeBytesAvailable, liTotalBytes, liTotalFreeBytes;

    if (!GetDiskFreeSpaceEx(lpcwstrDriver, &liFreeBytesAvailable, &liTotalBytes, &liTotalFreeBytes))
    {
        qDebug() << "ERROR: Call to GetDiskFreeSpaceEx() failed.";
        return 0;
    }

    return transformUnit((qint64)liTotalFreeBytes.QuadPart);
}

void NewTaskWindow::paintEvent(QPaintEvent *event)
{
    // 绘制窗口背景色;
    QPainter painter(this);
    QPainterPath pathBack;
    pathBack.setFillRule(Qt::WindingFill);
    pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()), 3, 3);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.fillPath(pathBack, QBrush(QColor(255, 255, 255)));

    // 绘制窗口上方蓝条;
    QPainterPath pathHead;
    pathHead.setFillRule(Qt::WindingFill);
    pathHead.addRoundedRect(QRect(0, 0, this->width(), 2), 3, 3);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.fillPath(pathHead, QBrush(QColor(15, 151, 255)));

    return QWidget::paintEvent(event);
}

// 根据输入下载url,请求获取文件信息l
void NewTaskWindow::getFileTotalSize(QString strUrl, int tryTimes)
{
    qint64 fileSize = -1;
    bool isGetResult = false;

    if (tryTimes <= 0)
    {
        tryTimes = 1;
    }

    do
    {
        // 如果有代理需要设置代理;
//      QNetworkProxy proxy;
//      proxy.setType(QNetworkProxy::HttpProxy);
//      proxy.setHostName("proxy.example.com");
//      proxy.setPort(1080);
//      proxy.setUser("username");
//      proxy.setPassword("password");
//      QNetworkProxy::setApplicationProxy(proxy);

        QNetworkAccessManager manager;
        // 事件循环,等待请求文件头信息结束;
        QEventLoop loop;
        // 超时,结束事件循环;
        QTimer timer;

        //发出请求,获取文件地址的头部信息;
        QNetworkReply *reply = manager.head(QNetworkRequest(strUrl));
        if (!reply)
            continue;

        connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

        timer.start(2000);
        loop.exec();

        if (reply->error() != QNetworkReply::NoError)
        {
            // 请求发生错误;
            qDebug() << reply->errorString();
            continue;
        }
        else if (!timer.isActive())
        {
            // 请求超时超时,未获取到文件信息;
            qDebug() << "Request Timeout";
            continue;
        }

        timer.stop();

        isGetResult = true;
        // 获取文件大小;
        QVariant var = reply->header(QNetworkRequest::ContentLengthHeader);
        fileSize = var.toLongLong();
        // 获取文件名;
        // 先根据请求返回的信息中获取文件名,因为有些文件服务器未必会返回文件名信息(包括文件名,文件大小);可使用下面方法;
        // QFileInfo 会根据 url 返回 下载文件名;但也会失败,返回为空值;
        QString strDisposition = reply->rawHeader("Content-Disposition");
        int index = strDisposition.indexOf("filename=");
        QString fileName = strDisposition.mid(index + 9);
        if (fileName.isEmpty())
        {
            QUrl url(strUrl);
            QFileInfo fileInfo(url.path());
            fileName += fileInfo.fileName();
        }

        showFileInfo(fileName , transformUnit(fileSize));

        reply->deleteLater();

        break;
    } while (tryTimes--);

    if (!isGetResult)
    {
        hideFileInfo();
    }
}

// 转换单位;
QString NewTaskWindow::transformUnit(double bytes)
{
    QString strUnit = " B";
    if (bytes <= 0)
    {
        bytes = 0;
    }
    else if (bytes < UNIT_KB)
    {
    }
    else if (bytes < UNIT_MB)
    {
        bytes /= UNIT_KB;
        strUnit = " KB";
    }
    else if (bytes < UNIT_GB)
    {
        bytes /= UNIT_MB;
        strUnit = " MB";
    }
    else if (bytes > UNIT_GB)
    {
        bytes /= UNIT_GB;
        strUnit = " GB";
    }
    // 保留小数点后两位;
    return QString("%1%2").arg(QString::number(bytes, 'f', 2)).arg(strUnit);
}

// 设置文件信息;
void NewTaskWindow::setFileInfo(QString fileName, QString fileType, QString fileSize)
{
    QTableWidgetItem *pTableItemName = new QTableWidgetItem();
    pTableItemName->setText(fileName);
    pTableItemName->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    ui.tableWidget->setItem(0, 0, pTableItemName);

    QTableWidgetItem *pTableItemContent = new QTableWidgetItem();
    pTableItemContent->setText(fileType);
    pTableItemContent->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    ui.tableWidget->setItem(0, 1, pTableItemContent);

    QTableWidgetItem *pTableItemTime = new QTableWidgetItem();
    pTableItemTime->setText(fileSize);
    pTableItemTime->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    ui.tableWidget->setItem(0, 2, pTableItemTime);
}

// 显示文件信息栏目;
void NewTaskWindow::showFileInfo(QString fileName , QString fileSize)
{
    ui.pButtonBT->setVisible(false);
    ui.pButtonPL->setVisible(false);

    ui.lineEdit->setVisible(true);
    ui.pButtonOpenFolder->setVisible(true);
    ui.tableWidget->setVisible(true);
    ui.tableWidget->clear();

    // 设置表头样式的代码需添加在 确定表格行列数后 才能生效;
    QStringList qsHeader;
    qsHeader << QStringLiteral("文件名") << QStringLiteral("类型") << QStringLiteral("大小");
    ui.tableWidget->setHorizontalHeaderLabels(qsHeader);
    ui.tableWidget->insertRow(0);
    ui.tableWidget->setRowHeight(0, 25);

    QString fileType = QFileInfo(fileName).suffix();
    setFileInfo(fileName, fileType, fileSize);

    this->setFixedHeight(335);
}

// 隐藏文件信息栏目;
void NewTaskWindow::hideFileInfo()
{
    ui.tableWidget->setVisible(false);
    ui.lineEdit->setVisible(false);
    ui.pButtonOpenFolder->setVisible(false);

    ui.pButtonBT->setVisible(true);
    ui.pButtonPL->setVisible(true);

    this->setFixedHeight(250);
}

// 请求链接输入框文字发送变换,主要是用于输入链接后自动请求文件信息;
void NewTaskWindow::onTextChanged()
{
    QString strUrl = ui.textEdit->toPlainText();
    getFileTotalSize(strUrl);
}

// 打开文件选择框选择文件夹;
void NewTaskWindow::onOpenFolder()
{
    QString filePath = QFileDialog::getExistingDirectory(this, QStringLiteral("迅雷下载"), m_filePath, QFileDialog::ShowDirsOnly);
    if (!filePath.isEmpty())
    {
        m_filePath = filePath;

        QString reaminSpace = QStringLiteral("剩余:%1").arg(getDiskFreeSpace(m_filePath));
        m_remainSpaceLabel->setText(reaminSpace);
        ui.lineEdit->setText(m_filePath);
    }   
}
  •  

界面设计图

这里写图片描述 这里写图片描述

代码分析

1、文件信息表格栏目

静态效果 (左为模仿的例子,右为迅雷窗口)

这里写图片描述 这里写图片描述

动态效果

这里写图片描述 这里写图片描述

本次界面的主要难点在于如何设置QTableWidget的样式,在网上找了半天资料,终于实现了跟迅雷一样的效果。

主要是去除去除原始边框,自己重新设置,在上面代码 initTableWidget()方法对其进行了初始化,但是样式并不满足,这就需要加载样式表。

样式表中主要是是控制鼠标对其进行操作比如鼠标选中、点击、悬浮等,不同状态下显示的样式。

/**********表头**********/
QHeaderView{
        color: rgb(183 , 183 , 183);
        background: transparent;
        border: none;
        min-height: 25px;
}
QHeaderView::section:horizontal {
        background: transparent;
        padding-left:6px;
        border:none;
        border-right: 1px solid rgb(202, 212, 219);
}
QHeaderView::section:horizontal:hover {
        background: transparent;
}
QHeaderView::section:horizontal:pressed {
        background: rgb(224, 224, 224);
}

/**********表格**********/
QTableView {
        color:black;
        border: 1px solid rgb(202, 212, 219);
        border-top: transparent;
}

QTableView::item{
        color:black;
        background:transparent;    
        padding-left:5px;
}

QTableView::item:selected{
        color:black;
        background:transparent;     
}

QTableView::item:hover{
        color:black;
        background:rgb(205,233,249);    
}

2、文件路径栏目内嵌QLabel显示剩余空间

这里写图片描述

这里写图片描述

可以参考代码中initFilePathLineEdit()方法的实现。

3、获取文件信息

主要是通过发送HTTP请求得到文件的文件名以及文件大小,但是这个需要看文件服务器是否支持,并不是所有的Url链接都会返回文件名或者文件大小。

4、整个效果演示

下面我测试了几条下载链接,并获取到了文件的信息。有时候文件大小会返回0B,可以尝试重新输入Url,看返回结果,在代码中我设置了2s请求超时时钟,如果2s之后,服务器还是没返回结果就结束请求。这里可以根据需要自定义时长。

这里写图片描述


花了近两个晚上的时间完成了迅雷新建任务窗口的模拟,外观效果基本上与迅雷一致(仍有欠缺,待完善),后期会继续模拟迅雷9的任务列表界面,以及实现真正的新建任务,并完成下载功能,敬请期待哈 O(∩_∩)O!

同时也很感谢一去、二三里群主大大博客的支持,赞一个!!!

Keep Moving 、 Keep Coding 、 啦啦啦 !!!


这里写图片描述

代码下载

Qt 之 模仿迅雷 新建任务界面 根据Url获取文件信息 exe

Qt 之 模仿迅雷 新建任务窗口 根据Url获取文件信息 源码

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值