<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #(66):訪問網絡(2) 上一章我們了解了`NetWorker`類的簡單實現。不僅如此,我們還提到了幾個 C++ 開發時常用的設計模式。這些在接下來得代碼中依然會用到。 現在我們先來研究下?[OpenWeatherMap 的相關 API](http://api.openweathermap.org/api)。之所以選擇 OpenWeatherMap,主要是因為這個網站提供了簡潔的 API 接口,非常適合示例程序,并且其開發也不需要額外申請 App ID。OpenWeatherMap 的 API 可以選擇返回 JSON 或者 XML,這里我們選擇使用 JSON 格式。在進行查詢時,OpenWeatherMap 支持使用城市名、地理經緯度以及城市 ID,為簡單起見,我們選擇使用城市名。我們先來看一個例子:[http://api.openweathermap.org/data/2.5/weather?q=Beijing,cn&mode=json&units=metric&lang=zh_cn](http://api.openweathermap.org/data/2.5/weather?q=Beijing,cn&mode=json&units=metric&lang=zh_cn)。下面是這個鏈接的參數分析: | 參數名字 | 傳入值 | 說明 | | -- || -- | | q | Beijing,cn | 查詢中國北京的天氣 | | mode | json | 返回格式為 JSON | | units | metric | 返回單位為公制 | | lang | zh_cn | 返回語言為中文 | 點擊鏈接,服務器返回一個 JSON 字符串(此時你應該能夠使用瀏覽器看到這個字符串): ~~~ {"coord":{"lon":116.397232,"lat":39.907501},"sys":{"country":"CN","sunrise":1381530122,"sunset":1381570774},"weather":[{"id":800,"main":"Clear","description":"晴","icon":"01d"}],"base":"gdps stations","main":{"temp":20,"pressure":1016,"humidity":34,"temp_min":20,"temp_max":20},"wind":{"speed":2,"deg":50},"clouds":{"all":0},"dt":1381566600,"id":1816670,"name":"Beijing","cod":200} ~~~ 我們從[這里](http://bugs.openweathermap.org/projects/api/wiki/Weather_Data)找到 JSON 各個字段的含義。現在我們關心的是:時間(dt);氣溫(temp);氣壓(pressure);濕度(humidity)和天氣狀況(weather)。基于此,我們設計了`WeatherInfo`類,用于封裝服務器返回的信息: ~~~ class WeatherDetail { public: WeatherDetail(); ~WeatherDetail(); QString desc() const; void setDesc(const QString &desc); QString icon() const; void setIcon(const QString &icon); private: class Private; friend class Private; Private *d; }; class WeatherInfo { public: WeatherInfo(); ~WeatherInfo(); QString cityName() const; void setCityName(const QString &cityName); quint32 id() const; void setId(quint32 id); QDateTime dateTime() const; void setDateTime(const QDateTime &dateTime); float temperature() const; void setTemperature(float temperature); float humidity() const; void setHumidity(float humidity); float pressure() const; void setPressure(float pressure); QList<WeatherDetail *> details() const; void setDetails(const QList<WeatherDetail *> details); private: class Private; friend class Private; Private *d; }; QDebug operator <<(QDebug dbg, const WeatherDetail &w); QDebug operator <<(QDebug dbg, const WeatherInfo &w); ~~~ `WeatherInfo`和`WeatherDetail`兩個類相互合作存儲我們所需要的數據。由于是數據類,所以只有單純的 setter 和 getter 函數,這里不再把源代碼寫出來。值得說明的是最后兩個全局函數: ~~~ QDebug operator <<(QDebug dbg, const WeatherDetail &w); QDebug operator <<(QDebug dbg, const WeatherInfo &w); ~~~ 我們重寫了`<<`運算符,以便能夠使用類似`qDebug() << weatherInfo;`這樣的語句進行調試。它的實現是這樣的: ~~~ QDebug operator <<(QDebug dbg, const WeatherDetail &w) { dbg.nospace() << "(" << "Description: " << w.desc() << "; " << "Icon: " << w.icon() << ")"; return dbg.space(); } QDebug operator <<(QDebug dbg, const WeatherInfo &w) { dbg.nospace() << "(" << "id: " << w.id() << "; " << "City name: " << w.cityName() << "; " << "Date time: " << w.dateTime().toString(Qt::DefaultLocaleLongDate) << ": " << endl << "Temperature: " << w.temperature() << ", " << "Pressure: " << w.pressure() << ", " << "Humidity: " << w.humidity() << endl << "Details: ["; foreach (WeatherDetail *detail, w.details()) { dbg.nospace() << "( Description: " << detail->desc() << ", " << "Icon: " << detail->icon() << "), "; } dbg.nospace() << "] )"; return dbg.space(); } ~~~ 這兩個函數雖然比較長,但是很簡單,這里不再贅述。 下面我們來看主窗口: ~~~ class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: class Private; friend class Private; Private *d; }; ~~~ 正如前面所說的,這里依然使用了 d 指針模式。頭文件沒有什么可說的。`MainWindow::Private`的實現依舊簡單: ~~~ class MainWindow::Private { public: Private() { netWorker = NetWorker::instance(); } void fetchWeather(const QString &cityName) const { netWorker->get(QString("http://api.openweathermap.org/data/2.5/weather?q=%1&mode=json&units=metric&lang=zh_cn").arg(cityName)); } NetWorker *netWorker; }; ~~~ 我們將`MainWindow`所需要的`NetWorker`作為`MainWindow::Private`的一個成員變量。`MainWindow::Private`提供了一個`fetchWeather()`函數。由于`NetWorker`提供的函數都是相當底層的,為了提供業務級別的處理,我們將這樣的函數封裝在`MainWindow::Private`中。當然,你也可以在`NetWorker`中直接提供類似的函數,這取決于你的系統分層設計。 ~~~ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), d(new MainWindow::Private) { QComboBox *cityList = new QComboBox(this); cityList->addItem(tr("Beijing"), QLatin1String("Beijing,cn")); cityList->addItem(tr("Shanghai"), QLatin1String("Shanghai,cn")); cityList->addItem(tr("Nanjing"), QLatin1String("Nanjing,cn")); QLabel *cityLabel = new QLabel(tr("City: "), this); QPushButton *refreshButton = new QPushButton(tr("Refresh"), this); QHBoxLayout *cityListLayout = new QHBoxLayout; cityListLayout->setDirection(QBoxLayout::LeftToRight); cityListLayout->addWidget(cityLabel); cityListLayout->addWidget(cityList); cityListLayout->addWidget(refreshButton); QVBoxLayout *weatherLayout = new QVBoxLayout; weatherLayout->setDirection(QBoxLayout::TopToBottom); QLabel *cityNameLabel = new QLabel(this); weatherLayout->addWidget(cityNameLabel); QLabel *dateTimeLabel = new QLabel(this); weatherLayout->addWidget(dateTimeLabel); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget); mainLayout->addLayout(cityListLayout); mainLayout->addLayout(weatherLayout); setCentralWidget(mainWidget); resize(320, 120); setWindowTitle(tr("Weather")); connect(d->netWorker, &NetWorker::finished, [=] (QNetworkReply *reply) { qDebug() << reply; QJsonParseError error; QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error == QJsonParseError::NoError) { if (!(jsonDocument.isNull() || jsonDocument.isEmpty()) && jsonDocument.isObject()) { QVariantMap data = jsonDocument.toVariant().toMap(); WeatherInfo weather; weather.setCityName(data[QLatin1String("name")].toString()); QDateTime dateTime; dateTime.setTime_t(data[QLatin1String("dt")].toLongLong()); weather.setDateTime(dateTime); QVariantMap main = data[QLatin1String("main")].toMap(); weather.setTemperature(main[QLatin1String("temp")].toFloat()); weather.setPressure(main[QLatin1String("pressure")].toFloat()); weather.setHumidity(main[QLatin1String("humidity")].toFloat()); QVariantList detailList = data[QLatin1String("weather")].toList(); QList<WeatherDetail *> details; foreach (QVariant w, detailList) { QVariantMap wm = w.toMap(); WeatherDetail *detail = new WeatherDetail; detail->setDesc(wm[QLatin1String("description")].toString()); detail->setIcon(wm[QLatin1String("icon")].toString()); details.append(detail); } weather.setDetails(details); cityNameLabel->setText(weather.cityName()); dateTimeLabel->setText(weather.dateTime().toString(Qt::DefaultLocaleLongDate)); } } else { QMessageBox::critical(this, tr("Error"), error.errorString()); } reply->deleteLater(); }); connect(refreshButton, &QPushButton::clicked, [=] () { d->fetchWeather(cityList->itemData(cityList->currentIndex()).toString()); }); } MainWindow::~MainWindow() { delete d; d = 0; } ~~~ 接下來我們來看`MainWindow`的構造函數和析構函數。構造函數雖然很長但是并不復雜,主要是對界面的構建。我們這里略過這些界面的代碼,直接看兩個信號槽的連接。 ~~~ connect(d->netWorker, &NetWorker::finished, [=] (QNetworkReply *reply) { QJsonParseError error; QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error == QJsonParseError::NoError) { if (!(jsonDocument.isNull() || jsonDocument.isEmpty()) && jsonDocument.isObject()) { QVariantMap data = jsonDocument.toVariant().toMap(); WeatherInfo weather; weather.setCityName(data[QLatin1String("name")].toString()); QDateTime dateTime; dateTime.setTime_t(data[QLatin1String("dt")].toLongLong()); weather.setDateTime(dateTime); QVariantMap main = data[QLatin1String("main")].toMap(); weather.setTemperature(main[QLatin1String("temp")].toFloat()); weather.setPressure(main[QLatin1String("pressure")].toFloat()); weather.setHumidity(main[QLatin1String("humidity")].toFloat()); QVariantList detailList = data[QLatin1String("weather")].toList(); QList<WeatherDetail *> details; foreach (QVariant w, detailList) { QVariantMap wm = w.toMap(); WeatherDetail *detail = new WeatherDetail; detail->setDesc(wm[QLatin1String("description")].toString()); detail->setIcon(wm[QLatin1String("icon")].toString()); details.append(detail); } weather.setDetails(details); cityNameLabel->setText(weather.cityName()); dateTimeLabel->setText(weather.dateTime().toString(Qt::DefaultLocaleLongDate)); } } else { QMessageBox::critical(this, tr("Error"), error.errorString()); } reply->deleteLater(); }); connect(refreshButton, &QPushButton::clicked, [=] () { d->fetchWeather(cityList->itemData(cityList->currentIndex()).toString()); }); ~~~ 由于使用了 Qt5,我們選擇新的連接語法。第一個`connect()`函數中,我們按照 API 文檔中描述的那樣對服務器返回的 JSON 字符串進行解析,然后將數據填充到一個`WeatherInfo`的對象。然后操作界面的兩個控件顯示數據。值得注意的是函數的最后一行,`reply->deleteLater();`。當網絡請求結束時,delete 服務器返回的`QNetworkReply`對象是用戶的責任。用戶需要選擇一個恰當的時機進行 delete 操作。但是,我們不能直接在`finiahed()`信號對應的槽函數中調用`delete`運算符。相反,我們需要使用`deleteLater()`函數,正如前面代碼中顯示的那樣。第二個槽函數則相對簡單,僅僅是重新獲取新的數據。 選擇我們可以運行下程序了: [![](https://box.kancloud.cn/2015-12-29_56823274bbd0d.png)](http://files.devbean.net/images/2013/10/weather-demo.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看