


【源码获取】
链接:https://pan.baidu.com/s/1QzHKZPXjkpx2p5TWUS_acA?pwd=5xsd
提取码:5xsd
>>>QProgressDialog 是 Qt 框架中的一个类,主要用于显示一个进度对话框,通常用在执行长时间操作时,以便让用户了解当前操作的进度。它可以用来进行反馈,显示任务的完成情况。
>>>QNetworkAccessManager 是 Qt 框架中的一个类,主要用于处理网络请求,包括发送和接收数据。它提供了一个高级的接口来执行 HTTP、HTTPS 和 FTP 等协议的网络操作。
>>>QUrl 是 Qt 框架中的一个类,用于表示和处理 URL(统一资源定位符)。它提供了一种便捷的方式来解析和构造 URL,以及进行相关的操作。
>>><memory> 是 C++ 标准库中的一个头文件,主要提供智能指针和内存管理的功能。它的引入旨在简化内存管理,减少内存泄漏的风险,并提高代码的安全性和可维护性。
>>>QNetworkReply 是 Qt 框架中的一个类,用于处理网络请求的响应。它与 QNetworkAccessManager 一起使用,用于接收来自网络服务的异步响应数据。
>>>QSslError 是 Qt 框架中的一个类,主要用于表示与 SSL(安全套接字层)相关的错误。它通常在使用 QSslSocket 或 QNetworkReply 进行安全网络通信时被用到。
>>>QAuthenticator 是 Qt 框架中的一个类,用于处理网络认证过程中的用户身份验证信息。它主要与 QNetworkAccessManager 和 QNetworkReply 类一起使用,以便在进行 HTTP 认证时,提供必需的用户名和密码。
>>>

QT += network widgets # 添加网络模块和小部件模块到项目中,以便使用它们提供的功能HEADERS += httpwindow.h # 将 httpwindow.h 文件添加到头文件列表中SOURCES += httpwindow.cpp \ # 将 httpwindow.cpp 文件添加到源文件列表中 main.cpp # 将 main.cpp 文件添加到源文件列表中FORMS += authenticationdialog.ui # 将 authenticationdialog.ui 文件添加到表单文件列表中# installtarget.path = $$[QT_INSTALL_EXAMPLES]/network/http # 设置安装目标路径为 Qt 示例目录下的 network/httpINSTALLS += target # 添加安装目标到 INSTALLS 列表中DISTFILES += \ # 指定要分发的文件列表 CMakeLists.txt # 添加 CMakeLists.txt 文件到分发文件中>>>#include <QProgressDialog> // 用于显示下载进度的对话框 #include <QNetworkAccessManager> // 处理网络请求的核心类 #include <QUrl> #include <memory> // 使用智能指针管理资源
#ifndef HTTPWINDOW_H#define HTTPWINDOW_H#include <QProgressDialog> // 用于显示下载进度的对话框#include <QNetworkAccessManager> // 处理网络请求的核心类#include <QUrl>#include <memory> // 使用智能指针管理资源// 前向声明:声明了一些Qt类,以便在代码中使用,避免包含不必要的头文件QT_BEGIN_NAMESPACEclass QFile;class QLabel;class QLineEdit;class QPushButton;class QSslError;class QAuthenticator;class QNetworkReply;class QCheckBox;#if QT_CONFIG(networkproxy) // 检查Qt库是否启用了网络代理class QNetworkProxy;#endifQT_END_NAMESPACE// 进度对话框类class ProgressDialog : public QProgressDialog { Q_OBJECTpublic: explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr);public slots: void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);};// 登录框类class HttpWindow : public QDialog{ Q_OBJECTpublic: explicit HttpWindow(QWidget *parent = nullptr); ~HttpWindow(); void startRequest(const QUrl &requestedUrl);private slots: void downloadFile(); void cancelDownload(); void httpFinished(); void httpReadyRead(); void enableDownloadButton(); void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator);#if QT_CONFIG(ssl) void sslErrors(const QList<QSslError> &errors);#endif#if QT_CONFIG(networkproxy) void slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);#endifprivate: std::unique_ptr<QFile> openFileForWrite(const QString &fileName); QLabel *statusLabel; QLineEdit *urlLineEdit; QPushButton *downloadButton; QCheckBox *launchCheckBox; QLineEdit *defaultFileLineEdit; QLineEdit *downloadDirectoryLineEdit; QUrl url; QNetworkAccessManager netAccessManager; QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply; std::unique_ptr<QFile> file; bool httpRequestAborted = false;};#endif>>>#include <QtWidgets> // 引入 QtWidgets 模块,提供创建图形用户界面 (GUI) 的类和功能 #include <QtNetwork> // 引入 QtNetwork 模块,提供网络编程相关的类和功能 #include <QUrl> // 引入 QUrl 类,用于处理 URL(统一资源定位符) #include <algorithm> // 引入标准算法库,提供常用的算法功能,如排序、查找等 #include <memory> // 引入内存管理库,提供智能指针等内存管理工具
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释
* // 包含头文件#include "httpwindow.h"#include "ui_authenticationdialog.h"#include <QtWidgets>#include <QtNetwork>#include <QUrl>#include <algorithm>#include <memory>// 判断是否配置了SSL#if QT_CONFIG(ssl)const char defaultUrl[] = "https://www.qt.io/"; // SSL连接时的默认URL#elseconst char defaultUrl[] = "http://www.qt.io/"; // 非SSL连接时的默认URL#endifconst char defaultFileName[] = "index.html"; // 默认文件名// 进度对话框构造函数ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent) : QProgressDialog(parent){ setWindowTitle(tr("下载进度")); // 设置窗口标题 setLabelText(tr("下载中... %1.").arg(url.toDisplayString())); // 设置标签文本 setMinimum(0); // 设置最小值 setValue(0); // 设置当前值 setMinimumDuration(0); // 设置最小持续时间 setMinimumSize(QSize(400, 75)); // 设置最小窗口大小}// 更新下载进度void ProgressDialog::networkReplyProgress(qint64 bytesRead, qint64 totalBytes){ setMaximum(totalBytes); // 设置最大值为总字节数 setValue(bytesRead); // 设置当前值为已读取的字节数}// HTTP窗口构造函数HttpWindow::HttpWindow(QWidget *parent) : QDialog(parent) , statusLabel(new QLabel(tr("请输入要下载的文件的URL.\n\n"), this)) // 状态标签 , urlLineEdit(new QLineEdit(defaultUrl)) // URL输入框 , downloadButton(new QPushButton(tr("下载"))) // 下载按钮 , launchCheckBox(new QCheckBox(tr("启动文件"))) // 启动文件复选框 , defaultFileLineEdit(new QLineEdit(defaultFileName)) // 默认文件名输入框 , downloadDirectoryLineEdit(new QLineEdit) // 下载目录输入框{ setWindowTitle(tr("HTTP Client")); // 设置窗口标题 // 连接认证请求信号与槽 connect(&netAccessManager, &QNetworkAccessManager::authenticationRequired, this, &HttpWindow::slotAuthenticationRequired);#if QT_CONFIG(networkproxy) // 连接代理认证请求信号与槽 connect(&netAccessManager, &QNetworkAccessManager::proxyAuthenticationRequired, this, &HttpWindow::slotProxyAuthenticationRequired);#endif QFormLayout *formLayout = new QFormLayout; // 创建表单布局 urlLineEdit->setClearButtonEnabled(true); // 启用清除按钮 connect(urlLineEdit, &QLineEdit::textChanged, this, &HttpWindow::enableDownloadButton); // 连接文本变化信号与槽 formLayout->addRow(tr("&URL:"), urlLineEdit); // 添加URL输入框到布局 // 获取下载目录 QString downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); if (downloadDirectory.isEmpty() || !QFileInfo(downloadDirectory).isDir()) downloadDirectory = QDir::currentPath(); // 如果为空则使用当前路径 downloadDirectoryLineEdit->setText(QDir::toNativeSeparators(downloadDirectory)); // 设置下载目录文本框 formLayout->addRow(tr("&Download directory:"), downloadDirectoryLineEdit); // 添加下载目录到布局 formLayout->addRow(tr("Default &file:"), defaultFileLineEdit); // 添加默认文件名到布局 launchCheckBox->setChecked(true); // 默认勾选启动文件复选框 formLayout->addRow(launchCheckBox); // 添加复选框到布局 QVBoxLayout *mainLayout = new QVBoxLayout(this); // 创建主布局 mainLayout->addLayout(formLayout); // 添加表单布局到主布局 mainLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); // 添加空白项以扩展布局 statusLabel->setWordWrap(true); // 启用换行 mainLayout->addWidget(statusLabel); // 添加状态标签到主布局 downloadButton->setDefault(true); // 设置下载按钮为默认按钮 connect(downloadButton, &QAbstractButton::clicked, this, &HttpWindow::downloadFile); // 连接下载按钮点击信号与槽 QPushButton *quitButton = new QPushButton(tr("Quit")); // 创建退出按钮 quitButton->setAutoDefault(false); // 设置不为默认按钮 connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close); // 连接退出按钮点击信号与槽 QDialogButtonBox *buttonBox = new QDialogButtonBox; // 创建对话框按钮框 buttonBox->addButton(downloadButton, QDialogButtonBox::ActionRole); // 添加下载按钮 buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); // 添加退出按钮 mainLayout->addWidget(buttonBox); // 添加按钮框到主布局 urlLineEdit->setFocus(); // 设置URL输入框为焦点}// HttpWindow析构函数HttpWindow::~HttpWindow() = default;// 启动请求void HttpWindow::startRequest(const QUrl &requestedUrl){ qDebug() << "HttpWindow::startRequest requestedUrl = " << requestedUrl.toDisplayString(); url = requestedUrl; // 设置请求的URL httpRequestAborted = false; // 重置请求中止标志 reply.reset(netAccessManager.get(QNetworkRequest(url))); // 发送GET请求并保存响应 // 连接请求完成信号与槽 connect(reply.get(), &QNetworkReply::finished, this, &HttpWindow::httpFinished); // 连接有数据可读信号与槽 connect(reply.get(), &QIODevice::readyRead, this, &HttpWindow::httpReadyRead);#if QT_CONFIG(ssl) // 连接SSL错误信号与槽 connect(reply.get(), &QNetworkReply::sslErrors, this, &HttpWindow::sslErrors);#endif ProgressDialog *progressDialog = new ProgressDialog(url, this); // 创建进度对话框 progressDialog->setAttribute(Qt::WA_DeleteOnClose); // 关闭时删除对话框 connect(progressDialog, &QProgressDialog::canceled, this, &HttpWindow::cancelDownload); // 连接取消信号与槽 connect(reply.get(), &QNetworkReply::downloadProgress, progressDialog, &ProgressDialog::networkReplyProgress); // 连接下载进度信号与槽 connect(reply.get(), &QNetworkReply::finished, progressDialog, &ProgressDialog::hide); // 连接请求完成信号与槽 progressDialog->show(); // 显示进度对话框 statusLabel->setText(tr("下载 %1...").arg(url.toString())); // 显示下载状态}// 下载文件void HttpWindow::downloadFile(){ const QString urlSpec = urlLineEdit->text().trimmed(); // 获取URL文本 if (urlSpec.isEmpty()) return; // 如果为空则返回 const QUrl newUrl = QUrl::fromUserInput(urlSpec); // 创建URL对象 if (!newUrl.isValid()) { // 验证URL有效性 QMessageBox::information(this, tr("错误"), tr("无效 URL: %1: %2").arg(urlSpec, newUrl.errorString())); // 显示错误信息 return; } QString fileName = newUrl.fileName(); // 获取文件名 qDebug() << "HttpWindow::downloadFile fileName = " << fileName << endl; if (fileName.isEmpty()) fileName = defaultFileLineEdit->text().trimmed(); // 如果文件名为空则使用默认文件名 if (fileName.isEmpty()) fileName = defaultFileName; // 如果仍为空则使用硬编码默认文件名 QString downloadDirectory = QDir::cleanPath(downloadDirectoryLineEdit->text().trimmed()); // 清理下载目录路径 bool useDirectory = !downloadDirectory.isEmpty() && QFileInfo(downloadDirectory).isDir(); // 检查下载目录有效性 if (useDirectory) fileName.prepend(downloadDirectory + '/'); // 如果有效则在文件名前加上目录 if (QFile::exists(fileName)) { // 检查文件是否已存在 QString alreadyExists = useDirectory ? tr("已存在名为%1的文件。覆盖?") : tr("当前目录中已存在名为%1的文件。" "覆盖?"); QMessageBox::StandardButton response = QMessageBox::question(this, tr("覆盖现有文件"), alreadyExists.arg(QDir::toNativeSeparators(fileName)), // 显示确认覆盖提示 QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (response == QMessageBox::No) return; // 如果选择不覆盖则返回 QFile::remove(fileName); // 删除已存在的文件 } file = openFileForWrite(fileName); // 打开文件以写入 if (!file) return; // 如果文件打开失败则返回 downloadButton->setEnabled(false); // 禁用下载按钮 // 调度请求 startRequest(newUrl);}// 返回用于写入的文件的std::unique_ptr<QFile>std::unique_ptr<QFile> HttpWindow::openFileForWrite(const QString &fileName){ // 创建 QFile 对象并打开用于写入 std::unique_ptr<QFile> file = std::make_unique<QFile>(fileName); if (!file->open(QIODevice::WriteOnly)) { // 校验文件是否成功打开 QMessageBox::information(this, tr("错误"), tr("无法保存文件 %1: %2.") .arg(QDir::toNativeSeparators(fileName), file->errorString())); // 显示错误信息 return nullptr; // 返回空指针 } return file; // 返回文件指针}// 取消下载void HttpWindow::cancelDownload(){ statusLabel->setText(tr("下载已取消。")); // 更新状态标签 httpRequestAborted = true; // 设置请求中止标志 reply->abort(); // 中止请求 downloadButton->setEnabled(true); // 启用下载按钮}// 请求完成void HttpWindow::httpFinished(){ qDebug() << "HttpWindow::httpFinished fileName = " << file.get()->fileName() << endl; QFileInfo fi; // 文件信息对象 if (file) { fi.setFile(file->fileName()); // 设置文件信息 file->close(); // 关闭文件 file.reset(); // 重置文件指针 } // 检查请求是否有错误 QNetworkReply::NetworkError error = reply->error(); const QString &errorString = reply->errorString(); reply.reset(); // 重置响应指针 if (error != QNetworkReply::NoError) { // 如果发生错误 QFile::remove(fi.absoluteFilePath()); // 删除已存在的文件 if (!httpRequestAborted) { // 如果不是用户中止 // 使用 QMessageBox 显示错误信息 QMessageBox::warning(this, tr("下载错误"), tr("下载失败:\n%1.").arg(errorString)); statusLabel->setText(tr("下载失败:\n%1.").arg(errorString)); // 更新状态标签以显示下载失败信息 downloadButton->setEnabled(true); // 启用下载按钮 } return; } statusLabel->setText(tr("已下载 %1 bytes to %2\nin\n%3") .arg(fi.size()) .arg(fi.fileName(), QDir::toNativeSeparators(fi.absolutePath()))); // 显示下载成功信息 if (launchCheckBox->isChecked()) QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath())); // 如果勾选了启动文件,则打开文件 downloadButton->setEnabled(true); // 启用下载按钮}// 下载就绪处理void HttpWindow::httpReadyRead(){ // 每当 QNetworkReply 有新数据时调用此槽。 // 读取所有新数据并写入文件中。 if (file) file->write(reply->readAll()); // 将新数据写入到文件}// 启用下载按钮void HttpWindow::enableDownloadButton(){ downloadButton->setEnabled(!urlLineEdit->text().isEmpty()); // 根据URL输入框内容决定按钮是否可用}// 处理认证请求void HttpWindow::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator){ qDebug() << "HttpWindow::slotAuthenticationRequired authenticator = " << authenticator << endl; QDialog authenticationDialog; // 创建认证对话框 Ui::Dialog ui; ui.setupUi(&authenticationDialog); // 设置对话框UI authenticationDialog.adjustSize(); // 调整对话框大小 ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm(), url.host())); // 设置描述 // 如果URL包含凭证信息,则填充UI ui.userEdit->setText(url.userName()); // 填充用户名 ui.passwordEdit->setText(url.password()); // 填充密码 if (authenticationDialog.exec() == QDialog::Accepted) { // 如果用户接受认证 authenticator->setUser(ui.userEdit->text()); // 设置用户名 authenticator->setPassword(ui.passwordEdit->text()); // 设置密码 }}#if QT_CONFIG(ssl)// 处理SSL错误void HttpWindow::sslErrors(const QList<QSslError> &errors){ qDebug() << "HttpWindow::sslErrors errors.size = " << errors.size() << endl; QString errorString; // 错误字符串 for (const QSslError &error : errors) { // 遍历所有错误 if (!errorString.isEmpty()) errorString += '\n'; // 添加换行 errorString += error.errorString(); // 收集错误信息 } // 显示错误信息并询问用户忽略错误 if (QMessageBox::warning(this, tr("TLS 错误"), tr("发生了一个或多个TLS错误:\n%1").arg(errorString), QMessageBox::Ignore | QMessageBox::Abort) == QMessageBox::Ignore) { reply->ignoreSslErrors(); // 忽略SSL错误 }}#endif#if QT_CONFIG(networkproxy)// 处理代理认证请求void HttpWindow::slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator){ qDebug() << "HttpWindow::slotProxyAuthenticationRequired proxy.user() = " <<proxy.user() << endl; QDialog authenticationDialog; // 创建认证对话框 Ui::Dialog ui; ui.setupUi(&authenticationDialog); // 设置对话框UI authenticationDialog.adjustSize(); // 调整对话框大小 ui.siteDescription->setText(tr("位于%1的网络代理正在请求域的凭据: %2") .arg(proxy.hostName(), authenticator->realm())); // 设置描述 // 如果用户在URL中提供了凭证,则填充UI ui.userEdit->setText(proxy.user()); // 填充代理用户名 ui.passwordEdit->setText(proxy.password()); // 填充代理密码 if (authenticationDialog.exec() == QDialog::Accepted) { // 如果用户接受认证 authenticator->setUser(ui.userEdit->text()); // 设置用户名 authenticator->setPassword(ui.passwordEdit->text()); // 设置密码 }}#endif
*/#include <QApplication>#include <QDir>#include <QScreen>// 这个项目的主要功能是下载网页文件#include "httpwindow.h"int main(int argc, char *argv[]){ QApplication app(argc, argv); // 居中显示处理 HttpWindow httpWin; const QRect availableSize = httpWin.screen()->availableGeometry(); qDebug() << "main availableSize = " << availableSize << endl; httpWin.resize(availableSize.width() / 5, availableSize.height() / 5); httpWin.move((availableSize.width() - httpWin.width()) / 2, (availableSize.height() - httpWin.height()) / 2); httpWin.show(); return app.exec();}
# 指定CMake的最低版本要求cmake_minimum_required(VERSION 3.16)# 定义项目名称为"http",指定使用的编程语言为C++project(http LANGUAGES CXX)# 查找所需的Qt6包,要求包含Core、Gui、Network和Widgets模块find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)# 设置项目的标准配置qt_standard_project_setup()# 添加可执行文件目标,指定其源文件和UI文件qt_add_executable(http authenticationdialog.ui # UI文件 httpwindow.cpp httpwindow.h # C++源文件和头文件 main.cpp # 主程序入口文件)# 设置目标属性,指示这是一个Windows可执行文件和macOS应用程序包set_target_properties(http PROPERTIES WIN32_EXECUTABLE TRUE # 对于Windows系统,指定为GUI应用程序(不会带有控制台) MACOSX_BUNDLE TRUE # 对于macOS,指定为应用程序包)# 指定链接库,设置目标与Qt6模块的链接target_link_libraries(http PRIVATE Qt6::Core # 链接Qt6的Core模块 Qt6::Gui # 链接Qt6的Gui模块 Qt6::Network # 链接Qt6的Network模块 Qt6::Widgets # 链接Qt6的Widgets模块)# 安装目标设置,定义了安装时文件的目标位置install(TARGETS http BUNDLE DESTINATION . # 安装应用程序包到当前目录 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # 运行时可执行文件安装到指定的运行时按件目录 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # 安装库文件到指定的库目录)# 生成用于部署应用程序的脚本qt_generate_deploy_app_script( TARGET http # 指定目标 OUTPUT_SCRIPT deploy_script # 输出脚本文件名 NO_UNSUPPORTED_PLATFORM_ERROR # 不报错于不支持的平台)# 安装部署脚本install(SCRIPT ${deploy_script}) # 将生成的部署脚本安装到构建目录原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。