# 主项目入口
main函数创建对象空间,确认窗口的大小和坐标。
#include <QApplication>
#include <QDir>
#include <QScreen> //
#include <QDebug>
#include "httpwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
HttpWindow httpWin; // QDialog的子类
const QRect availableSize = httpWin.screen()->availableGeometry();
qDebug()<<"availableSize = "<<availableSize;
// 窗口高度和宽度为当前电脑屏幕的五分之一
httpWin.resize(availableSize.width() / 5, availableSize.height() / 5);
// 坐标(x,y)在电脑的正中间
httpWin.move((availableSize.width() - httpWin.width()) / 2, (availableSize.height() - httpWin.height()) / 2);
httpWin.show(); // 显示界面
return app.exec();
}
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目视频教程+代码,C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓
# 项目子头文件httpwindow.h
需要的头文件:
QT_BEGIN_NAMESPACE
class QFile; // 文件
class QLabel; // 标签
class QLineEdit; // 行编辑
class QPushButton; // 按钮
class QSslError; // QSslError类提供SSL错误
class QAuthenticator; // QAuthenticator类提供了一个身份验证对象。
class QNetworkReply; // 网络应答
class QCheckBox; // 检查盒子
QT_END_NAMESPACE
根据给出的类名,以下是各个类的作用的简要介绍:
1. QFile(文件):QFile类提供了对文件的读写操作。它可以用于打开、关闭、读取和写入文件,并提供了一些用于文件操作的便捷方法。
2. QLabel(标签):QLabel类用于显示文本或图像。它通常用于在用户界面中显示静态文本或图像,并且不允许用户进行编辑操作。
3. QLineEdit(行编辑):QLineEdit类提供了一个单行文本编辑框,用于接收用户输入的文本。它可以用于接收单行的用户输入,比如用户名、密码等。
4. QPushButton(按钮):QPushButton类是一个按钮部件,用于触发某些操作或执行特定的功能。当用户单击按钮时,可以连接按钮的信号(clicked)到槽函数,从而实现相关的操作。
5. QSslError(SSL错误):QSslError类提供了有关SSL连接中发生的错误的信息。它用于处理与SSL(Secure Sockets Layer 安全套接字层)相关的错误,如证书验证失败、主机名不匹配等。
6. QAuthenticator(身份验证对象):QAuthenticator类提供了一个身份验证对象,用于在进行网络请求时进行身份验证。它可以用于管理用户名和密码等身份验证信息,并与网络请求一起使用。
7. QNetworkReply:QNetworkReply类用于表示网络请求的响应。它提供了访问响应数据、处理错误和其他网络相关操作的方法。
8. QCheckBox:QCheckBox类是一个复选框部件,用于允许用户选择多个选项。它可以用于表示二进制状态,比如打开/关闭、选中/未选中等。
class ProgressDialog : public QProgressDialog {
Q_OBJECT
public:
explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr);
~ProgressDialog();
public slots:
void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);
};
代码解释:
ProgressDialog类的作用是显示一个进度对话框,用于显示网络请求的进度。它通常用于在进行网络请求时显示一个进度条,以便用户可以看到请求的进展情况。
构造函数ProgressDialog(const QUrl &url, QWidget *parent = nullptr)接受一个QUrl类型的参数和一个可选的父部件参数。它用于创建一个ProgressDialog对象,并指定要进行网络请求的URL。
析构函数~ProgressDialog()用于在ProgressDialog对象被销毁时进行清理工作。
networkReplyProgress(qint64 bytesRead, qint64 totalBytes)是一个公共槽函数(public slot),用于处理网络请求的进度更新。它接受两个参数:bytesRead表示已读取的字节数,totalBytes表示总字节数。该槽函数可以在网络请求的过程中更新进度对话框的进度条。
通过继承自QProgressDialog类,ProgressDialog类可以使用QProgressDialog类提供的功能,如设置进度条的范围、设置进度文本等。
class HttpWindow : public QDialog
{
Q_OBJECT
public:
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);
#ifndef QT_NO_SSL
void sslErrors(QNetworkReply *, const QList<QSslError> &errors);
#endif
private:
std::unique_ptr<QFile> openFileForWrite(const QString &fileName);
QLabel *statusLabel;
QLineEdit *urlLineEdit;
QPushButton *downloadButton;
QCheckBox *launchCheckBox;
QLineEdit *defaultFileLineEdit;
QLineEdit *downloadDirectoryLineEdit;
QUrl url;
QNetworkAccessManager qnam;
QNetworkReply *reply;
std::unique_ptr<QFile> file;
bool httpRequestAborted; // http请求已中止
};
代码解释:
HttpWindow类的作用是提供一个界面,用于进行HTTP请求和文件下载操作。它包含了一些用于处理HTTP请求和文件下载的槽函数,并使用了Qt的网络模块(QNetworkAccessManager和QNetworkReply)进行网络通信。
构造函数`HttpWindow(QWidget *parent = nullptr)`接受一个可选的父部件参数,并用于创建一个HttpWindow对象。析构函数`~HttpWindow()`用于在HttpWindow对象被销毁时进行清理工作。
`startRequest(const QUrl &requestedUrl)`函数用于开始进行HTTP请求。它接受一个QUrl类型的参数,表示要请求的URL。该函数会初始化网络请求,并发送HTTP请求到指定的URL。
槽函数`downloadFile()`、`cancelDownload()`、`httpFinished()`、`httpReadyRead()`、`enableDownloadButton()`、`slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator)`和`sslErrors(QNetworkReply *, const QList<QSslError> &errors)`分别用于处理下载文件、取消下载、HTTP请求完成、HTTP请求可读、启用下载按钮、处理身份验证和处理SSL错误等操作。
`openFileForWrite(const QString &fileName)`函数是一个私有函数,用于打开一个文件以供写入。它接受一个文件名参数,并返回一个指向QFile的唯一指针,用于写入文件。
HttpWindow类还包含了一些成员变量,如statusLabel(标签部件,用于显示状态信息)、urlLineEdit(行编辑部件,用于输入URL)、downloadButton(按钮部件,用于触发文件下载)、launchCheckBox(复选框部件,用于选择是否启动下载后的文件)、defaultFileLineEdit(行编辑部件,用于指定默认的下载文件名)和downloadDirectoryLineEdit(行编辑部件,用于指定下载文件的目录)等。
## httpwindow.h
#ifndef HTTPWINDOW_H
#define HTTPWINDOW_H
#include <QProgressDialog>
#include <QNetworkAccessManager>
#include <QUrl>
#include <memory>
QT_BEGIN_NAMESPACE
class QFile; // 文件
class QLabel; // 标签
class QLineEdit; // 行编辑
class QPushButton; // 按钮
class QSslError; // QSslError类提供SSL错误
class QAuthenticator; // QAuthenticator类提供了一个身份验证对象。
class QNetworkReply;
class QCheckBox;
QT_END_NAMESPACE
class ProgressDialog : public QProgressDialog {
Q_OBJECT
public:
explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr);
~ProgressDialog();
public slots:
void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);
};
class HttpWindow : public QDialog
{
Q_OBJECT
public:
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);
#ifndef QT_NO_SSL
void sslErrors(QNetworkReply *, const QList<QSslError> &errors);
#endif
private:
std::unique_ptr<QFile> openFileForWrite(const QString &fileName);
QLabel *statusLabel;
QLineEdit *urlLineEdit;
QPushButton *downloadButton;
QCheckBox *launchCheckBox;
QLineEdit *defaultFileLineEdit;
QLineEdit *downloadDirectoryLineEdit;
QUrl url;
QNetworkAccessManager qnam;
QNetworkReply *reply;
std::unique_ptr<QFile> file;
bool httpRequestAborted;
};
#endif
## 源文件httpwindow.cpp
#include "httpwindow.h"
#include "ui_authenticationdialog.h"
#include <QtWidgets>
#include <QtNetwork>
#include <QUrl>
#if QT_CONFIG(ssl) // #if QT_CONFIG(ssl) 的目的是检查 Qt 库是否已配置 SSL 模块
const char defaultUrl[] = "https://www.baidu.com/";
#else
const char defaultUrl[] = "https://www.baidu.com/";
#endif
const char defaultFileName[] = "index.html"; // 默认文件名
ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent)
: QProgressDialog(parent)
{
this->setWindowTitle(tr("Download Progress"));
this->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); // 移除 WindowContextHelpButtonHint。WindowContextHelpButtonHint 是一个标志,用于表示窗口是否应显示帮助按钮
this->setLabelText(tr("Downloading %1.").arg(url.toDisplayString())); // 显示正在下载的文件的名称
this->setMinimum(0);
this->setValue(0);
this->setMinimumDuration(0);
this->setMinimumSize(QSize(400, 75)); // 最小窗口
}
ProgressDialog::~ProgressDialog()
{
}
void ProgressDialog::networkReplyProgress(qint64 bytesRead, qint64 totalBytes)
{
setMaximum(totalBytes);
setValue(bytesRead);
}
HttpWindow::HttpWindow(QWidget *parent)
: QDialog(parent)
, statusLabel(new QLabel(tr("Please enter the URL of a file you want to download.\n\n"), this))
, urlLineEdit(new QLineEdit(defaultUrl))
, downloadButton(new QPushButton(tr("Download")))
, launchCheckBox(new QCheckBox("Launch file"))
, defaultFileLineEdit(new QLineEdit(defaultFileName))
, downloadDirectoryLineEdit(new QLineEdit)
, reply(nullptr)
, file(nullptr)
, httpRequestAborted(false)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("HTTP"));
connect(&qnam, &QNetworkAccessManager::authenticationRequired,
this, &HttpWindow::slotAuthenticationRequired);
#ifndef QT_NO_SSL
connect(&qnam, &QNetworkAccessManager::sslErrors,
this, &HttpWindow::sslErrors);
#endif
QFormLayout *formLayout = new QFormLayout;
urlLineEdit->setClearButtonEnabled(true);
connect(urlLineEdit, &QLineEdit::textChanged,
this, &HttpWindow::enableDownloadButton);
formLayout->addRow(tr("&URL:"), urlLineEdit);
QString downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
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();
}
HttpWindow::~HttpWindow()
{
}
void HttpWindow::startRequest(const QUrl &requestedUrl)
{
url = requestedUrl;
httpRequestAborted = false;
reply = qnam.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &HttpWindow::httpFinished);
connect(reply, &QIODevice::readyRead, this, &HttpWindow::httpReadyRead);
ProgressDialog *progressDialog = new ProgressDialog(url, this);
progressDialog->setAttribute(Qt::WA_DeleteOnClose);
connect(progressDialog, &QProgressDialog::canceled, this, &HttpWindow::cancelDownload);
connect(reply, &QNetworkReply::downloadProgress, progressDialog, &ProgressDialog::networkReplyProgress);
connect(reply, &QNetworkReply::finished, progressDialog, &ProgressDialog::hide);
progressDialog->show();
statusLabel->setText(tr("Downloading %1...").arg(url.toString()));
}
void HttpWindow::downloadFile()
{
const QString urlSpec = urlLineEdit->text().trimmed();
if (urlSpec.isEmpty())
return;
const QUrl newUrl = QUrl::fromUserInput(urlSpec);
if (!newUrl.isValid()) {
QMessageBox::information(this, tr("Error"),
tr("Invalid URL: %1: %2").arg(urlSpec, newUrl.errorString()));
return;
}
QString fileName = newUrl.fileName();
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)) {
if (QMessageBox::question(this, tr("Overwrite Existing File"),
tr("There already exists a file called %1%2."
" Overwrite?")
.arg(fileName,
useDirectory
? QString()
: QStringLiteral(" in the current directory")),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No)
== QMessageBox::No) {
return;
}
QFile::remove(fileName);
}
file = openFileForWrite(fileName);
if (!file)
return;
downloadButton->setEnabled(false);
// schedule the request
startRequest(newUrl);
}
std::unique_ptr<QFile> HttpWindow::openFileForWrite(const QString &fileName)
{
std::unique_ptr<QFile> file(new QFile(fileName));
if (!file->open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("Error"),
tr("Unable to save the file %1: %2.")
.arg(QDir::toNativeSeparators(fileName),
file->errorString()));
return nullptr;
}
return file;
}
void HttpWindow::cancelDownload()
{
statusLabel->setText(tr("Download canceled."));
httpRequestAborted = true;
reply->abort();
downloadButton->setEnabled(true);
}
void HttpWindow::httpFinished()
{
QFileInfo fi;
if (file) {
fi.setFile(file->fileName());
file->close();
file.reset();
}
if (httpRequestAborted) {
reply->deleteLater();
reply = nullptr;
return;
}
if (reply->error()) {
QFile::remove(fi.absoluteFilePath());
statusLabel->setText(tr("Download failed:\n%1.").arg(reply->errorString()));
downloadButton->setEnabled(true);
reply->deleteLater();
reply = nullptr;
return;
}
const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
reply->deleteLater();
reply = nullptr;
if (!redirectionTarget.isNull()) {
const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());
if (QMessageBox::question(this, tr("Redirect"),
tr("Redirect to %1 ?").arg(redirectedUrl.toString()),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
QFile::remove(fi.absoluteFilePath());
downloadButton->setEnabled(true);
statusLabel->setText(tr("Download failed:\nRedirect rejected."));
return;
}
file = openFileForWrite(fi.absoluteFilePath());
if (!file) {
downloadButton->setEnabled(true);
return;
}
startRequest(redirectedUrl);
return;
}
statusLabel->setText(tr("Downloaded %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有新数据时,就会调用此插槽。
//我们读取它的所有新数据并将其写入文件。
//这样,我们使用的RAM比在finished()时读取时要少
//QNetworkReply的信号
if (file)
file->write(reply->readAll());
}
void HttpWindow::enableDownloadButton()
{
downloadButton->setEnabled(!urlLineEdit->text().isEmpty());
}
void HttpWindow::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator)
{
QDialog authenticationDialog;
Ui::Dialog ui;
ui.setupUi(&authenticationDialog);
authenticationDialog.adjustSize();
ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm(), url.host()));
//URL是否包含信息?填充UI
//只有当URL提供的凭据错误时,这才相关
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());
}
}
#ifndef QT_NO_SSL
void HttpWindow::sslErrors(QNetworkReply *, const QList<QSslError> &errors)
{
QString errorString;
for (const QSslError &error : errors) {
if (!errorString.isEmpty())
errorString += '\n';
errorString += error.errorString();
}
if (QMessageBox::warning(this, tr("SSL Errors"),
tr("One or more SSL errors has occurred:\n%1").arg(errorString),
QMessageBox::Ignore | QMessageBox::Abort) == QMessageBox::Ignore) {
reply->ignoreSslErrors();
}
}
#endif
## ui文件
效果演示
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目视频教程+代码,C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓