QT开发学习笔记(网络下载实例 )

网络下载实例

Qt 网 络 模 块 还 提 供 了 直 接 访 问 如 HTTP , FTP 等 网 络 协 议 的 类 , 这 些 类 是

QNetworkAccessManager、QNetworkRequest 和 QNetworkReply。

通常需要这三个类协作才能完成一个网络操作。可以用于从网络获取时间,天气和图片等
等数据。比如本例需要下载一张图片,大概流程如下。

由 QNetworkRequest 类设置一个 URL 地址发起网络协议请求,QNetworkRequest 类保存要
用 QNetworkAccessManager 发送的请求。QNetworkRequest 是网络访问 API 的一部分,是一个
持有通过网络发送请求所需信息的类。它包含一个 URL 和一些可用于修改请求的辅助信息。
QNetworkAccessManager 类允许应用程序发送网络请求并接收响应。在 QNetworkRequest

发起网络请求后,QNetworkAccessManager 负责发送网络请求,创建网络响应。
QNetworkReply类就用于 QNetworkAccessManager 创建的网络响应。最终由QNetworkReply

处理网络响应。它提供了 finished()、readyRead()和 downloadProgress()等信号,可以监测网络响
应的执行情况。并且 QNetworkReply 继承于 QIODevice,所以 QNetworkReply 支持流读写,可
以直接用 read()和 write 等功能。

11.4.1 应用实例

本例目的:了解 QNetworkAccessManager、QNetworkRequest 和 QNetworkReply 类的使用。

例 12_imagedownload,下载小图片(难度:一般)。项目路径为 Qt/2/12_imagedownload。
本例大体流程,设置一个下载图片的 URL,通过 networkReply 处理响应后,从流中读取图片的
数据,然后保存到本地。

项目文件 12_imagedownload.pro 文件第一行添加的代码部分如下。

12_imagedownload.pro 编程后的代码

1 QT += core gui network 

2 

3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 

4 

5 CONFIG += c++11 

6 

7 # The following define makes your compiler emit warnings if you use 

8 # any Qt feature that has been marked deprecated (the exact warnings 

9 # depend on your compiler). Please consult the documentation of the 

10 # deprecated API in order to know how to port your code away from it. 

11 DEFINES += QT_DEPRECATED_WARNINGS 

12 

13 # You can also make your code fail to compile if it uses deprecated APIs. 

14 # In order to do so, uncomment the following line. 

15 # You can also select to disable deprecated APIs only up to a certain 
version of Qt. 

16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the 
APIs deprecated before Qt 6.0.0 

17 

18 SOURCES += \ 

19 main.cpp \ 

20 mainwindow.cpp 

21 

22 HEADERS += \ 

23 mainwindow.h 

24 

25 # Default rules for deployment. 

26 qnx: target.path = /tmp/$${TARGET}/bin 

27 else: unix:!android: target.path = /opt/$${TARGET}/bin 

28 !isEmpty(target.path): INSTALLS += target 

在头文件“mainwindow.h”具体代码如下。

mainwindow.h 编程后的代码

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 12_imagedownload 
 * @brief mainwindow.h 
 * @author Deng Zhimao 
 * @email [email protected] 
 * @net www.openedv.com 
 * @date 2021-04-16 
 *******************************************************************/ 

1 #ifndef MAINWINDOW_H 

2 #define MAINWINDOW_H 

3 

4 #include <QMainWindow> 

5 #include <QNetworkAccessManager> 

6 #include <QNetworkReply> 

7 #include <QFile> 

8 #include <QLabel> 

9 #include <QPushButton> 

10 #include <QProgressBar> 

11 #include <QHBoxLayout> 

12 #include <QVBoxLayout> 

13 #include <QLineEdit> 

14 

15 class MainWindow : public QMainWindow 

16 { 

17 Q_OBJECT 

18 

19 public: 

20 MainWindow(QWidget *parent = nullptr); 

21 ~MainWindow(); 

22 private: 

23 /* 网络管理 */ 

24 QNetworkAccessManager *networkAccessManager; 

25 

26 /* 标签 */ 

27 QLabel *label[3]; 

28 

29 /* 按钮 */ 

30 QPushButton *pushButton; 

31 

32 /* 下载进度条 */ 

33 QProgressBar *progressBar; 

34 

35 /* 水平布局 */ 

36 QHBoxLayout *hBoxLayout[2]; 

37 

38 /* 垂直布局 */ 

39 QVBoxLayout *vBoxLayout; 

40 

41 /* 水平容器 */ 

42 QWidget *hWidget[2]; 

43 

44 /* 垂直容器 */ 

45 QWidget *vWidget; 

46 

47 /* 链接输入框 */ 

48 QLineEdit *lineEdit; 

49 

50 private slots: 

51 /* 读取数据 */ 

52 void readyReadData(); 

53 

54 /* 响应完成处理 */ 

55 void replyFinished(); 

56 

57 /* 下载进度管理 */ 

58 void imageDownloadProgress(qint64, qint64); 

59 

60 /* 点击开始下载 */ 

61 void startDownload(); 

62 

63 /* 响应错误处理函数 */ 

64 void networkReplyError(QNetworkReply::NetworkError); 

65 }; 

66 #endif // MAINWINDOW_H 

头文件里主要是声明界面用的元素,及一些槽函数。重点是声明 networkAccessManager。

在源文件“mainwindow.cpp”具体代码如下。

mainwindow.cpp 编程后的代码

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 12_imagedownload 
 * * @brief mainwindow.cpp 
 * @author Deng Zhimao 
 * @email [email protected] 
 * @net www.openedv.com 
 * @date 2021-04-16 
 *******************************************************************/ 

1 #include "mainwindow.h" 

2 #include <QMessageBox> 

3 #include <QCoreApplication> 

4 

5 MainWindow::MainWindow(QWidget *parent) 

6 : QMainWindow(parent) 

7 { 

8 /* 设置主窗体的位置与大小 */ 

9 this->setGeometry(0, 0, 800, 480); 

10 

11 /* 标签 0, 显示下载的图像 */ 

12 label[0] = new QLabel(); 

13 /* 标签 1, 显示 URL 标签 */ 

14 label[1] = new QLabel(); 

15 /* 下载进度标签 */ 

16 label[2] = new QLabel(); 

17 

18 /* 下载图片链接输入框 */ 

19 lineEdit = new QLineEdit(); 

20 

21 /* 下载按钮 */ 

22 pushButton = new QPushButton(); 

23 

24 /* 下载进度条 */ 

25 progressBar = new QProgressBar(); 

26 

27 /* 水平布局 */ 

28 hBoxLayout[0] = new QHBoxLayout(); 

29 hBoxLayout[1] = new QHBoxLayout(); 

30 

31 /* 垂直布局 */ 

32 vBoxLayout = new QVBoxLayout(); 

33 

34 /* 水平容器 */ 

35 hWidget[0] = new QWidget(); 

36 hWidget[1] = new QWidget(); 

37 
38 /* 垂直容器 */ 

39 vWidget = new QWidget(); 

40 

41 label[1]->setText("URL 链接:"); 

42 label[2]->setText("文件下载进度:"); 

43 

44 pushButton->setText("下载"); 

45 

46 /* 设置下载链接地址 */ 

47 lineEdit->setText("https://ss0.bdstatic.com/70cFuH" 

48 "Sh_Q1YnxGkpoWK1HF6hhy/it/u=42710" 

49 "87328,1384669424&fm=11&gp=0.jpg"); 

50 /* 设置标签的最小显示大小 */ 

51 label[0]->setMinimumSize(this->width(), 

52 this->height() * 0.75); 

53 

54 /* 根据文本文字大小自适应大小 */ 

55 label[1]->setSizePolicy(QSizePolicy::Fixed, 

56 QSizePolicy::Fixed); 

57 label[2]->setSizePolicy(QSizePolicy::Fixed, 

58 QSizePolicy::Fixed); 

59 pushButton->setSizePolicy(QSizePolicy::Fixed, 

60 QSizePolicy::Fixed); 

61 

62 /* 水平布局 0 添加元素 */ 

63 hBoxLayout[0]->addWidget(label[1]); 

64 hBoxLayout[0]->addWidget(lineEdit); 

65 hBoxLayout[0]->addWidget(pushButton); 

66 

67 /* 设置水平布局 0 为水平容器的布局 0 */ 

68 hWidget[0]->setLayout(hBoxLayout[0]); 

69 

70 /* 水平布局 1 添加元素 */ 

71 hBoxLayout[1]->addWidget(label[2]); 

72 hBoxLayout[1]->addWidget(progressBar); 

73 

74 /* 设置水平布局 1 为水平容器的布局 1 */ 

75 hWidget[1]->setLayout(hBoxLayout[1]); 

76 

77 /* 垂直布局添加元素 */ 

78 vBoxLayout->addWidget(label[0]); 

79 vBoxLayout->addWidget(hWidget[0]); 

80 vBoxLayout->addWidget(hWidget[1]); 

81 

82 /* 设置垂直布局为垂直容器的布局 */ 

83 vWidget->setLayout(vBoxLayout); 

84 

85 /* 设置居中 */ 

86 setCentralWidget(vWidget); 

87 

88 /* 网络管理 */ 

89 networkAccessManager = new QNetworkAccessManager(this); 

90 

91 /* 信号槽连接 */ 

92 connect(pushButton, SIGNAL(clicked()), 

93 this, SLOT(startDownload())); 

94 

95 } 

96 

97 MainWindow::~MainWindow() 

98 { 

99 } 

100 

101 void MainWindow::startDownload() 

102 { 

103 /* 获取 URL 链接 */ 

104 QUrl newUrl(QUrl(lineEdit->text())); 

105 

106 /* 如果下载链接无效,则直接返回 */ 

107 if (!newUrl.isValid()) { 

108 QMessageBox::information(this, "error", "invalid url"); 

109 return; 

110 } 

111 

112 /* 网络请求 */ 

113 QNetworkRequest networkRequest; 

114 

115 /* 设置下载的地址 */ 

116 networkRequest.setUrl(newUrl); 

117 

118 /* 网络响应 */ 

119 QNetworkReply *newReply = 

120 networkAccessManager->get(networkRequest); 

121 

122 /* 信号槽连接 */ 

123 connect(newReply, SIGNAL(finished()), 

124 this, SLOT(replyFinished())); 

125 connect(newReply, SIGNAL(readyRead()), 

126 this, SLOT(readyReadData())); 

127 connect(newReply, SIGNAL(downloadProgress(qint64, qint64)), 

128 this, SLOT(imageDownloadProgress(qint64, qint64))); 

129 connect(newReply, 

130 SIGNAL(error(QNetworkReply::NetworkError)), 

131 this, 

132 SLOT(networkReplyError(QNetworkReply::NetworkError ))); 

133 } 

134 

135 void MainWindow::readyReadData() 

136 { 

137 /* 设置按钮不可用,防止未完成,再次点击 */ 

138 pushButton->setEnabled(false); 

139 

140 /* 获取信号发送者 */ 

141 QNetworkReply *reply = (QNetworkReply *)sender(); 

142 

143 QFile imageFile; 

144 /* 保存到当前路径,名称为"下载的.jpg" */ 

145 imageFile.setFileName(QCoreApplication::applicationDirPath() 

146 + "/下载的.jpg"); 

147 

148 /* 如果此图片已经存在,则删除 */ 

149 if (imageFile.exists()) 

150 imageFile.remove(); 

151 

152 /* 读取数据 */ 

153 QByteArray data = reply->readAll(); 

154 /* 如果数据为空,返回 */ 

155 if (data.isEmpty()) { 

156 qDebug()<<"data is null, please try it again!"<<endl; 

157 return; 

158 } 

159 

160 /* 判断是不是 JPG 格式的图片,如果不是则返回 */ 

161 if (! (data[0] == (char)0xff 

162 && data[1] == (char)0xd8 

163 && data[data.size() - 2] == (char)0xff 

164 && data[data.size() - 1] == (char)0xd9)) { 

165 qDebug()<<"not JPG data, please try it again!"<<endl; 

166 return; 

167 } 

168 

169 /* 转为 QPixmap */ 

170 QPixmap pixmap; 

171 pixmap.loadFromData(data); 

172 pixmap.save(imageFile.fileName()); 

173 } 

174 

175 void MainWindow::replyFinished() 

176 { 

177 /* 获取信号发送者 */ 

178 QNetworkReply *reply = (QNetworkReply *)sender(); 

179 

180 /* 防止内存泄漏 */ 

181 reply->deleteLater(); 

182 

183 /* 判断当前执行程序下的图像是否下载完成 */ 

184 QFile imageFile(QCoreApplication::applicationDirPath() 

185 + "/下载的.jpg"); 

186 if (imageFile.exists()) { 

187 /* 显示下载的图像 */ 

188 label[0]->setPixmap(QPixmap(imageFile.fileName())); 

189 qDebug() <<"已经成功下载,文件路径为:" 

190 <<imageFile.fileName()<<endl; 

191 } else 

192 /* 清空显示 */ 

193 label[0]->clear(); 

194 

195 /* 设置按钮可用 */ 

196 pushButton->setEnabled(true); 

197 } 

198 

199 void MainWindow::imageDownloadProgress(qint64 bytes, 

200 qint64 totalBytes) 

201 { 

202 /* 设置进度条的最大值 */ 

203 progressBar->setMaximum(totalBytes); 

204 /* 设置当前值 */ 

205 progressBar->setValue(bytes); 

206 } 

207 
208 /* 网络响应处理函数 */ 

209 void MainWindow::networkReplyError(QNetworkReply::NetworkError 

210 error) 

211 { 

212 switch (error) { 

213 case QNetworkReply::ConnectionRefusedError: 

214 qDebug()<<"远程服务器拒绝连接"<<endl; 

215 break; 

216 case QNetworkReply::HostNotFoundError: 

217 qDebug()<<"找不到远程主机名"<<endl; 

218 break; 

219 case QNetworkReply::TimeoutError: 

220 qDebug()<<"与远程服务器连接超时"<<endl; 

221 break; 

222 default: 

223 break; 

224 } 

225 } 

第 89 行,全局变量 networkAccessManager 实例化。
第 101 行~133 行,首先从单行输入框里获取 URL 链接为 newUrl,判断链接的有效性。然
后创建局部变量 networkRequest,设置 networkRequest 请求 URL 为 newUrl。QNetworkReply
*newReply = networkAccessManager->get(networkRequest);为最重要的代码,所有响应本次的操
作都交给了 newReply。通过信号槽处理对应的操作。
第 135~173 行,这部分代码就是从 newReply 流里读取网络下载的数据。
第 160~167 行,这里笔者做了一些处理,从网络下载的数据可能遇到数据丢失或者下载错
误的情况。本例是从百度里下载一张 JPG 格式的图片,因为 JPG 图片的判断依据是第一个字节
和第二个字节的数据是 0xff 和 0xd8,倒数第一个和倒数第二个字节数据分别是 0xd9 和 0xff。
如果都对,那么判断此数据为 JPG 图片数据。然后进行保存,否则则不保存图片。处理数据往
往是需要的,我们经常要对下载的数据进行处理。
第 174~197 行,网络响应完成。记得要删除 reply,防止内存泄漏。如果下载成功图片,则
显示图片到 label[0]上。
第 209~225 行,网络响应错误处理函数。

11.4.2 程序运行效果

点击下载按钮后,可以看到本次下载的图片已经保存到当前编译输出的路径下,名字叫“下
载的.jpg”,并显示到界面上。由于文件下载的速度非常快,所以下载的进度条一下子就变成了

100%。若想看见下载进度条下载进度缓慢一些,可以修改本例去下载其他文件,注意不要保存
为 jpg 图片了。注意:此程序里的下载链接可能失效,请替换自己的图片链接。
QT开发学习笔记(网络下载实例 )_第1张图片

你可能感兴趣的:(QT开发学习笔记,qt,学习,开发语言)