Hello!我是你们的老朋友--泽哥!这一期我们介绍如何使用QT的QNetWork的库进行高级网络编程开发!并且简述软件的包装与发布!咱们快开始吧!
(一)界面文件
下拉框采取二级联动的方式,下面左边是今天的天气,右边是明天的天气。点击开始搜索,程序发送网页请求,读取XML文件的数据,读进StringList中。
(二)主体文件
MainWindow.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_MainWindow.h"
#include<QNetworkAccessManager>
#include<QXmlStreamReader>
#include<QNetworkRequest>
#include<QNetworkReply>
#include<QStringList>
#include<QTextcodec>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
void Init();
void showClear();
private slots:
void replyFinished(QNetworkReply*);
void ProvinceSlot(const QString &);
void WeatherSlot();
private:
Ui::MainWindow *ui;
QStringList List;
QNetworkAccessManager *caonima;
int choose;//槽函数的选项
QEventLoop eventLoop;
};
MainWindow.cpp
#include "MainWindow.h"
enum Tag
{
INIT_Province = 1,INIT_CITY,CHANGE_CITY,QUERY_WEATHER
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
caonima = new QNetworkAccessManager(this);
Init();//初始化界面
connect(ui->comboBoxProvince, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(ProvinceSlot(const QString &)));
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(WeatherSlot()));
}
//---初始化界面的时候天气预报的默认值隐藏不见
void MainWindow::showClear()
{
ui->labelImage1->clear();
ui->labelImage2->clear();
ui->labelTemperature->clear();
ui->labelWeather->clear();
ui->labelWind->clear();
// ui->labelToday->clear();
ui->labelTodayTips->clear();
ui->labelImage3->clear();
ui->labelImage4->clear();
ui->labelTemperature_2->clear();
ui->labelWeather_2->clear();
ui->labelWind_2->clear();
// ui->labelTomorrow->clear();
ui->labelTomorrowTips->clear();
}
//---查询天气的槽函数
void MainWindow::WeatherSlot()
{
choose = QUERY_WEATHER;
QString CityName = ui->comboBoxCity->currentText();
caonima->get(QNetworkRequest(QUrl("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=" + CityName)));
eventLoop.exec();
}
//---改变城市
void MainWindow::ProvinceSlot(const QString &ProvinceName)
{
choose = CHANGE_CITY;
caonima->get(QNetworkRequest(QUrl("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getSupportCity?byProvinceName=" + ProvinceName)));
eventLoop.exec();
}
//---网络请求槽函数
void MainWindow::replyFinished(QNetworkReply *reply)
{
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QString all = codec->toUnicode(reply->readAll());
QXmlStreamReader reader(all);
while (!reader.atEnd())
{
reader.readNext();
if (reader.isStartElement())
{
if (reader.name() == "string")
{
List.append(reader.readElementText());
}
}
}
switch (choose)
{
case INIT_Province:
{
for (QStringList::const_iterator citer = List.constBegin(); citer != List.constEnd(); citer++)
{
ui->comboBoxProvince->addItem(*citer);
}
ui->comboBoxProvince->setCurrentIndex(0);//默认显示的是第一项(直辖市)
break;
}
case INIT_CITY:
{
for (QStringList::const_iterator citer = List.constBegin(); citer != List.constEnd(); citer++)
{
QString str = citer->left(citer->indexOf(QChar(' ')));
ui->comboBoxCity->addItem(str);
}
ui->comboBoxCity->setCurrentIndex(0);//默认在列表中显示的是第一项(基本上为省会城市)
List.clear();
break;
}
case CHANGE_CITY:
{
ui->comboBoxCity->clear();
for (QStringList::const_iterator citer = List.constBegin(); citer != List.constEnd(); citer++)
{
QString str = citer->left(citer->indexOf(QChar(' ')));
ui->comboBoxCity->addItem(str);
}
ui->comboBoxCity->setCurrentIndex(0);
List.clear();
break;
}
case QUERY_WEATHER:
{
if (List.count() < 23) { return; }
QString strImage("rc//");
ui->labelImage1->setPixmap(QPixmap(strImage + List[8]));
ui->labelImage2->setPixmap(QPixmap(strImage + List[9]));
ui->labelTemperature->setText(List[5]);
ui->labelWind->setText(List[7]);
ui->labelTodayTips->setText(List[10]);
int tempIndex = List[11].indexOf(QChar(65292));
// QString temp = List[11].left(List[11].indexOf(QChar(':')));
QString temp = List[11].left(tempIndex);
temp = temp.mid(6);
ui->labelWeather->setText(temp);
ui->labelImage3->setPixmap(QPixmap(strImage + List[15]));
ui->labelImage4->setPixmap(QPixmap(strImage + List[16]));
ui->labelTemperature_2->setText(List[12]);
ui->labelWeather_2->setText(List[13]);
ui->labelWind_2->setText(List[14]);
ui->labelTomorrowTips->setText(List[22]);
List.clear();
break;
}
}
reply->deleteLater();
}
//---页面初始化
void MainWindow::Init()
{
//---初始化UI
setWindowTitle(QString::fromLocal8Bit("天气预报"));
setFixedSize(width(), height());
setWindowIcon(QIcon(QPixmap("rc//a_0.gif")));
Qt::WindowFlags flags = Qt::Dialog;
flags |= Qt::WindowMinimizeButtonHint;
flags |= Qt::WindowCloseButtonHint;
setWindowFlags(flags);
ui->labelLogo->setPixmap(QPixmap("rc//r_t1.gif"));
ui->labelCity->setPixmap(QPixmap("rc//r_b.gif"));
ui->labelTemperatureIcon->setPixmap(QPixmap("rc//tem1.gif"));
ui->labelZiWaiXianIcon->setPixmap(QPixmap("rc//tem3.gif"));
ui->labelDirectionIcon->setPixmap(QPixmap("rc//tem2.gif"));
ui->labelTemperatureIcon_2->setPixmap(QPixmap("rc//tem1.gif"));
ui->labelZiWaiXianIcon_2->setPixmap(QPixmap("rc//tem3.gif"));
ui->labelDirection_2->setPixmap(QPixmap("rc//tem2.gif"));
showClear();
choose = INIT_Province;//初始化省份列表(代号:1)
caonima->get(QNetworkRequest(QUrl("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getSupportProvince?")));//发送页面请求
connect(caonima, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
//---局部事件循环,当replyFinished完成后,caonima发送finished信号,才开始exec()后面的代码
// QEventLoop eventLoop;
connect(caonima, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
choose = INIT_CITY;//初始化城市列表(代号:2)
QString City = List.at(0);//默认省份列表第一项(直辖市)为默认省份
List.clear();
caonima->get(QNetworkRequest(QUrl("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getSupportCity?byProvinceName=" + City)));//发送请求
//---局部事件循环
connect(caonima, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
}
这个项目有以下几点需要注意一下:
1.一个项目只需开一个QNetworkAccessManager的对象即可,在构造函数中对其分配内存(new一个~)
2.enum枚举型是个好东西,基本上用它设置多个常量可以取代const和#define
3.XML的读取请戳这里QXmlStreamReader的用法详解
4.引入局部事件循环的方法,请戳这里!
这个xml读取到底是个啥流程呢?请看下面:执行QNetworkAccessManager的对象*caonima的方法get(URL),向服务器端发送XML文件请求,接收到服务器方的http报文之后,caonima会发送finished(QNetworkReply)的信号,执行对应的槽函数replyFinished(QNetworkReply),对http报文中的xml进行解析,读取数据,之后caonima发送QNetworkAccessManager::finished的信号,执行对应的槽函数quit(),执行eventLoop.exec()之后的程序。为啥这么做呢,因为网络请求的速度是很慢的,是异步的程序,为了防止一些变量还没等XML文件处理完就被别的程序段修改,咱们强制性的将异步的SML请求读取变为顺序执行。ok,讲到这里!