Qt on Android: http download and Json Parsing

Source: Internet
Author: User

Baidu provides an open interface for querying ip address locations. When you enter an ip address in the search box to search, the Baidu box application provided by ip138 will be opened, you can directly enter the ip address in the box to query. I checked the page request, extracted the interface for querying ip addresses, and wrote a simple ip address retrieval query application using Qt. It can run on a computer or Android phone. Baidu API is used here. It is hereby declared that it can only be used for demonstration purposes and cannot be used for commercial purposes.

Copyright foruok, reprinted please indicate the source (http://blog.csdn.net/foruok ).

This example uses http download, layout manager, edit box, button, Json parsing, and other knowledge. Figure 1: Enter the IP address on the mobile phone:


Figure 1 Ip address input

See figure 2, which is the result of the query after clicking the query button:


Figure 2 IP address attribution query results

Now let's talk about the program.

The project is created based on the Qt Widgets Application template, and QWidget is selected as the base class. For details about the creation process, see Qt on Android: Hello World full process. The project name is IpQuery. After the project is created, open the project file and add the network module for the QT variable, because we need to use it when querying the IP address. As shown in the following code:

QT       += core gui network
The project template generates the widget. h/widget. cpp for us. modify the code and build the interface first. First, let's look at the header file widget. h:

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QPushButton>#include <QLineEdit>#include <QLabel>#include "ipQuery.h"class Widget : public QWidget{    Q_OBJECTpublic:    Widget(QWidget *parent = 0);    ~Widget();protected slots:    void onQueryButton();    void onQueryFinished(bool bOK, QString ip, QString area);protected:    QLineEdit *m_ipEdit;    QPushButton *m_queryButton;    QLabel *m_areaLabel;    IpQuery m_ipQuery;};#endif // WIDGET_H

Let's look at the widget. cpp:
# Include "widget. h "# include <QGridLayout> Widget: Widget (QWidget * parent): QWidget (parent), m_ipQuery (this) {connect (& m_ipQuery, SIGNAL (finished (bool, QString, QString), this, SLOT (onQueryFinished (bool, QString, QString); QGridLayout * layout = new QGridLayout (this); layout-> setColumnStretch (1, 1 ); QLabel * label = new QLabel ("ip:"); layout-> addWidget (label, 0, 0); m_ipEdit = new QLineEdit (); layout-> AddWidget (m_ipEdit, 0, 1); m_queryButton = new QPushButton ("query"); connect (m_queryButton, SIGNAL (clicked (), this, SLOT (onQueryButton ())); layout-> addWidget (m_queryButton, 1, 1); m_areaLabel = new QLabel (); layout-> addWidget (m_areaLabel, 2, 0, 1, 2 ); layout-> setRowStretch (3, 1);} Widget ::~ Widget () {} void Widget: onQueryButton () {QString ip = m_ipEdit-> text (); if (! Ip. isEmpty () {m_ipQuery.query (ip); m_ipEdit-> setDisabled (true); m_queryButton-> setDisabled (true);} void Widget: onQueryFinished (bool bOK, QString ip, QString area) {if (bOK) {m_areaLabel-> setText (area);} else {m_areaLabel-> setText ("Oh, an error occurred ");} m_ipEdit-> setEnabled (true); m_queryButton-> setEnabled (true );}

The interface layout is simple. We use a QGridLayout to manage the ip address edit box, query button, and QLabel used to display the result. QGridLayout has addWidget ()/addLayout () and other methods to add controls or sub-la. There are also setColumnStretch ()/setRowStretch () Methods to set the coefficient of row and column stretching. In the example, set the stretching coefficient of the column where the ip editing box is located to 1, and set the tensile coefficient of the invisible 4th rows to 1, because the control of our applet cannot fill the entire mobile phone screen, in this way, the display on the mobile phone is normal.

I also connected the QPushButton signal clicked () to the onQueryButton () slot in the Widget constructor, and called the IpQuery class in the slot to Query ip addresses. In addition, the finished () signal of the IpQuery class is connected to the onQueryFinished () slot of the Widget class. After the query is completed, the result is displayed on the label represented by m_areaLabel.

Okay, the Widget has been explained. Let's take a look at the IpQuery class I implemented. We add two files in the project: ipQuery. h/ipQuery. cpp. First look at ipQuery. h:

#ifndef IPQUERY_H#define IPQUERY_H#include <QObject>#include <QNetworkAccessManager>#include <QNetworkReply>class IpQuery : public QObject{    Q_OBJECTpublic:    IpQuery(QObject *parent = 0);    ~IpQuery();    void query(const QString &ip);    void query(quint32 ip);signals:    void finished(bool bOK, QString ip, QString area);protected slots:    void onReplyFinished(QNetworkReply *reply);private:    QNetworkAccessManager m_nam;    QString m_emptyString;};

In the IpQuery class, two query () functions are declared, and ip addresses in QString and uint32 formats are accepted respectively. A finished () signal is also declared, which has a Boolean parameter bOK indicating success or not, the input ip address, and the returned region area. Finally, a slot onReplyFinished () is defined to respond to the finished () signal of the QNetworkAccessManager class.

See IpQuery. cpp again:

#include "ipQuery.h"#include <QJsonDocument>#include <QByteArray>#include <QHostAddress>#include <QJsonObject>#include <QNetworkRequest>#include <QJsonArray>#include <QTextCodec>#include <QDebug>IpQuery::IpQuery(QObject *parent)    : QObject(parent)    , m_nam(this){    connect(&m_nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(onReplyFinished(QNetworkReply*)));}IpQuery::~IpQuery(){}void IpQuery::query(const QString &ip){    QString strUrl = QString("http://opendata.baidu.com/api.php?query=%1&resource_id=6006&ie=utf8&format=json").arg(ip);    QUrl url(strUrl);    QNetworkRequest req(url);    req.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");    req.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36");    QNetworkReply *reply = m_nam.get(req);    reply->setProperty("string_ip", ip);}void IpQuery::query(quint32 ip){    QHostAddress addr(ip);    query(addr.toString());}void IpQuery::onReplyFinished(QNetworkReply *reply){    reply->deleteLater();    QString strIp = reply->property("string_ip").toString();    if(reply->error() != QNetworkReply::NoError)    {        qDebug() << "IpQuery, error - " << reply->errorString();        emit finished(false, strIp, m_emptyString);        return;    }    int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();    //qDebug() << "IpQuery, status - " << status ;    if(status != 200)    {        emit finished(false, strIp, m_emptyString);        return;    }    QByteArray data = reply->readAll();    QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();    //qDebug() << "contentType - " << contentType;    int charsetIndex = contentType.indexOf("charset=");    if(charsetIndex > 0)    {        charsetIndex += 8;        QString charset = contentType.mid(charsetIndex).trimmed().toLower();        if(charset.startsWith("gbk") || charset.startsWith("gb2312"))        {            QTextCodec *codec = QTextCodec::codecForName("GBK");            if(codec)            {                data = codec->toUnicode(data).toUtf8();            }        }    }    int parenthesisLeft = data.indexOf('(');    int parenthesisRight = data.lastIndexOf(')');    if(parenthesisLeft >=0 && parenthesisRight >=0)    {        parenthesisLeft++;        data = data.mid(parenthesisLeft, parenthesisRight - parenthesisLeft);    }    QJsonParseError err;    QJsonDocument json = QJsonDocument::fromJson(data, &err);    if(err.error != QJsonParseError::NoError)    {        qDebug() << "IpQuery, json error - " << err.errorString();        emit finished(false, strIp, m_emptyString);        return;    }    QJsonObject obj = json.object();    QJsonObject::const_iterator it = obj.find("data");    if(it != obj.constEnd())    {        QJsonArray dataArray = it.value().toArray();        QJsonObject info = dataArray.first().toObject();        QString area = info.find("location").value().toString();        emit finished(true, strIp, area);    }}

The implementation of IpQuery is simple and direct, initiating a network request to parse the returned Json data.

In the IpQuery constructor, I connect the finished () signal of QNetworkAccessManager TO THE onReplyFinished () slot of IpQuery.

The key functions include two queries (const QString &) and onReplyFinished (QNetworkReply *). First look at the query () function, which demonstrates the basic steps for http download using QNetworkAccessManager:

As for http header settings, QNetworkRequest provides the setHeader () method to set common headers such as User-Agent/Content-Type. Qt does not define common headers, you need to call the setRawHeader () method to set it. For more information, see http.

Now let's take a look at what the onReplyFinished () function has done:

According to the above explanation, it should be easy to understand everything. The steps 5 and 6 are explained here.

To convert GBK-encoded text data to UTF-8, follow these steps:

For more details, see the QTextCodec API documentation.

Finally, let's talk about Json data parsing. Since Qt 5.0, you have introduced support for Json. Before that, you may need to use the open-source cJson or QJson. Now, the official support is more practical.

Qt can parse Json data in the text format by using the QJsonDocument: fromJson () method. It can also parse Json data compiled as binary, using fromBinaryData () or fromRawData (). Corresponding, toJson () and toBinaryData () can be converted in reverse order.

Our example calls the fromJson () method to parse Json data in text format. FromJson () accepts Json data in UTF-8 format and a QJsonParseError object pointer to output possible errors. Once the fromJson () method is returned, Json data is parsed into various Json objects defined by Qt, such as QJsonObject, QJsonArray, and QJsonValue, you can use these methods to query the data you are interested in.

Let's make a simple introduction to science and explain the Json format.

JSON refers to the JavaScript Object Notation (JavaScript Object Notation). It is a lightweight text data exchange format and is self-descriptive and easy to understand. Although originated from the JavaScript language, it is independent of the language and platform.

Json has two data structures:

Json objects are represented in curly brackets. The simplest example is as follows:

{"ip":"36.57.177.187"}
As you can see, a pair of curly braces represents an object. Keys and values are separated by colons, while key-value pairs are separated by commas. An object can have multiple key-value pairs. The following are two examples:

{    "status":"0",    "t":"1401346439107"}

Json has six basic types of values: Boolean, floating point, String, array, object, and null. Now you can think of nesting. Yes: A value can be an object, and the object can be expanded and nested. A value can be an array, the array contains a series of basic types of values or objects ...... Therefore, using nesting can really express a very complex data structure, but it is actually not so easy to read ......

Json array is represented in square brackets. The simplest example is the basic type:

["baz", null, 1.0, 2]

Values in the array are separated by commas.

Let's look at a complex example:

[  "name":"zhangsan",   {    "age":30,    "phone":"13588888888",    "other": ["xian", null, 1.0, 28]  }]

The array contains simple string values, objects, and key-value pairs and arrays ......

In Qt, QJsonValue represents the value in Json, which has isDouble ()/isBool ()/isNull ()/isArray ()/isObject ()/isString () the following six methods are used to determine the value type: toDouble ()/toBool ()/toInt ()/toArray ()/toObject ()/toString () to convert QJsonValue to a specific type of value.

The QJsonObject class represents an object. Its find () method can find value based on the key, while keys () can return the list of all keys. It also reloads the "[]" operator, take the key in string format as the subscript. Let's use QJsonObject like an array.

The QJsonArray class represents an array. It has methods such as size ()/at ()/first ()/last (). Of course, it also loads the "[]" Operator (accept the subscript of the integer array ).

OK. Now, the basic knowledge has been introduced. Let's look at the Json data to be processed during ip address query:

{"Status": "0", "t": "1401346439107", "data": [{"location": "Suzhou Telecom, Anhui Province", "titlecont ": "ip address query", "origip": "36.57.177.187", "origipquery": "36.57.177.187", "showlamp": "1", "showLikeShare": 1, "your image ": 1, "ExtendedLocation": "", "OriginQuery": "36.57.177.187", "tplt": "ip", "resourceid": "6006", "fetchkey ": "36.57.177.187", "appinfo": "", "role_id": 0, "disp_type": 0}]}

The key named "data" in the root object is an array, and there is only one object in the array. The key named "location" in this object corresponds to the ip address's unique location. Well, it's very easy to look at the code in this format:

    QJsonParseError err;    QJsonDocument json = QJsonDocument::fromJson(data, &err);
The two rows generate the QJsonDocument object based on the data. Then let's look at the value corresponding to the key of the root object named "data" and check the Code:

    QJsonObject obj = json.object();    QJsonObject::const_iterator it = obj.find("data");
Find the value corresponding to data, convert toArray () to QJsonArray, use the first () method of QJsonArray to obtain the first element, convert toObject () to QJsonObject, and then use the find () method, search with "location" as the key and convert the result to String. The code is more clear:
        QJsonArray dataArray = it.value().toArray();        QJsonObject info = dataArray.first().toObject();        QString area = info.find("location").value().toString();        emit finished(true, strIp, area);

All right, this example is complete. Finally, let's take a look at the running effect on the computer, as shown in Figure 3:

Figure 3 computer running

Copyright foruok, reprinted please indicate the source (http://blog.csdn.net/foruok ).


My Qt on Android series articles:

  • Qt on Android: full process of Hello World
  • Introduction to Qt 5.2 for Android development in Windows
  • Analysis of the deployment process of Qt for Android
  • Qt on Android: Output Qt debugging information to logcat.
  • Qt on Android: Qt 5.3.0 released. Improvements for Android
  • Qt on Android Episode 1)
  • Qt on Android Episode 2)
  • Qt on Android Episode 3)
  • Qt on Android Episode 4)
  • Compiling a pure C project using Qt for Android
  • Compiling Android C language executable programs using Qt for Android in Windows
  • Qt on Android: Android SDK Installation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.