<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                #(65):訪問網絡(1) 現在的應用程序很少有純粹單機的。大部分為了各種目的都需要聯網操作。為此,Qt 提供了自己的網絡訪問庫,方便我們對網絡資源進行訪問。本章我們將介紹如何使用 Qt 進行最基本的網絡訪問。 Qt 進行網絡訪問的類是`QNetworkAccessManager`,這是一個名字相當長的類,不過使用起來并不像它的名字一樣復雜。為了使用網絡相關的類,你需要在 pro 文件中添加`QT += network`。 `QNetworkAccessManager`類允許應用程序發送網絡請求以及接受服務器的響應。事實上,Qt 的整個訪問網絡 API 都是圍繞著這個類進行的。`QNetworkAccessManager`保存發送的請求的最基本的配置信息,包含了代理和緩存的設置。最好的是,這個 API 本身就是異步設計,這意味著我們不需要自己為其開啟線程,以防止界面被鎖死(這里我們可以簡單了解下,Qt 的界面活動是在一個主線程中進行。網絡訪問是一個相當耗時的操作,如果整個網絡訪問的過程以同步的形式在主線程進行,則當網絡訪問沒有返回時,主線程會被阻塞,界面就會被鎖死,不能執行任何響應,甚至包括一個代表響應進度的滾動條都會被卡死在那里。這種設計顯然是不友好的。)。異步的設計避免了這一系列的問題,但是卻要求我們使用更多的代碼來監聽返回。這類似于我們前面提到的`QDialog::exec()`和`QDialog::show()`之間的區別。`QNetworkAccessManager`是使用信號槽來達到這一目的的。 一個應用程序僅需要一個`QNetworkAccessManager`類的實例。所以,雖然`QNetworkAccessManager`本身沒有被設計為單例,但是我們應該把它當做單例使用。一旦一個`QNetworkAccessManager`實例創建完畢,我們就可以使用它發送網絡請求。這些請求都返回`QNetworkReply`對象作為響應。這個對象一般會包含有服務器響應的數據。 下面我們用一個例子來看如何使用`QNetworkAccessManager`進行網絡訪問。這個例子不僅會介紹`QNetworkAccessManager`的使用,還將設計到一些關于程序設計的細節。 我們的程序是一個簡單的天氣預報的程序,使用 OpenWeatherMap 的 API 獲取數據。我們可以在[這里](http://api.openweathermap.org/api)找到其 API 的具體介紹。 我們前面說過,一般一個應用使用一個`QNetworkAccessManager`就可以滿足需要,因此我們自己封裝一個`NetWorker`類,并把這個類作為單例。注意,我們的代碼使用了 Qt5 進行編譯,因此如果你需要將代碼使用 Qt4 編譯,請自行修改相關部分。 ~~~ // !!! Qt5 #ifndef NETWORKER_H #define NETWORKER_H #include <QObject> class QNetworkReply; class NetWorker : public QObject { Q_OBJECT public: static NetWorker * instance(); ~NetWorker(); void get(const QString &url); signals: void finished(QNetworkReply *reply); private: class Private; friend class Private; Private *d; explicit NetWorker(QObject *parent = 0); NetWorker(const NetWorker &) Q_DECL_EQ_DELETE; NetWorker& operator=(NetWorker rhs) Q_DECL_EQ_DELETE; }; #endif // NETWORKER_H ~~~ `NetWorker`是一個單例類,因此它有一個`instance()`函數用來獲得這唯一的實例。作為單例模式,要求構造函數、拷貝構造函數和賦值運算符都是私有的,因此我們將這三個函數都放在 private 塊中。注意我們增加了一個`Q_DECL_EQ_DELETE`宏。這個宏是 Qt5 新增加的,意思是將它所修飾的函數聲明為 deleted(這是 C++11 的新特性)。如果編譯器支持`= delete`語法,則這個宏將會展開為`= delete`,否則則展開為空。我們的`NetWorker`只有一個`get`函數,顧名思義,這個函數會執行 HTTP GET 操作;一個信號`finished()`,會在獲取到服務器響應后發出。private 塊中還有三行關于`Private`的代碼: ~~~ class Private; friend class Private; Private *d; ~~~ 這里聲明了一個`NetWorker`的內部類,然后聲明了這個內部類的 d 指針。d 指針是 C++ 程序常用的一種設計模式。它的存在于 C++ 程序的編譯有關。在 C++ 中,保持二進制兼容性非常重要。如果你能夠保持二進制兼容,則當以后升級庫代碼時,用戶不需要重新編譯自己的程序即可直接運行(如果你使用 Qt5.0 編譯了一個程序,這個程序不需要重新編譯就可以運行在 Qt5.1 下,這就是二進制兼容;如果不需要修改源代碼,但是必須重新編譯才能運行,則是源代碼兼容;如果必須修改源代碼并且再經過編譯,例如從 Qt4 升級到 Qt5,則稱二者是不兼容的)。保持二進制兼容的很重要的一個原則是不要隨意增加、刪除成員變量。因為這會導致類成員的尋址偏移量錯誤,從而破壞二進制兼容。為了避免這個問題,我們將一個類的所有私有變量全部放進一個單獨的輔助類中,而在需要使用這些數據的類值提供一個這個輔助類的指針。注意,由于我們的輔助類是私有的,用戶不能使用它,所以針對這個輔助類的修改不會影響到外部類,從而保證了二進制兼容。關于二進制兼容的問題,我們會在以后的文章中更詳細的說明,這里僅作此簡單介紹。 下面來看`NetWorker`的實現。 ~~~ class NetWorker::Private { public: Private(NetWorker *q) : manager(new QNetworkAccessManager(q)) {} QNetworkAccessManager *manager; }; ~~~ `Private`是`NetWorker`的內部類,扮演者前面我們所說的那個輔助類的角色。`NetWorker::Private`類主要有一個成員變量`QNetworkAccessManager *`,把`QNetworkAccessManager`封裝起來。`NetWorker::Private`需要其被輔助的類`NetWorker`的指針,目的是作為`QNetworkAccessManager`的 parent,以便`NetWorker`析構時能夠自動將`QNetworkAccessManager`析構。當然,我們也可以通過將`NetWorker::Private`聲明為`QObject`的子類來達到這一目的。 ~~~ NetWorker *NetWorker::instance() { static NetWorker netWorker; return &netWorker; } ~~~ `instance()`函數很簡單,我們聲明了一個 static 變量,將其指針返回。這是 C++ 單例模式的最簡單寫法,由于 C++ 標準要求類的構造函數不能被打斷,因此這樣做也是線程安全的。 ~~~ NetWorker::NetWorker(QObject *parent) : QObject(parent), d(new NetWorker::Private(this)) { connect(d->manager, &QNetworkAccessManager::finished, this, &NetWorker::finished); } NetWorker::~NetWorker() { delete d; d = 0; } ~~~ 構造函數參數列表我們將 d 指針進行賦值。構造函數內容很簡單,我們將`QNetworkAccessManager`的`finished()`信號進行轉發。也就是說,當`QNetworkAccessManager`發出`finished()`信號時,`NetWorker`同樣會發出自己的`finished()`信號。析構函數將 d 指針刪除。由于`NetWorker::Private`是在堆上創建的,并且沒有繼承`QObject`,所以我們必須手動調用`delete`運算符。 ~~~ void NetWorker::get(const QString &url) { d->manager->get(QNetworkRequest(QUrl(url))); } ~~~ `get()`函數也很簡單,直接將用戶提供的 URL 字符串提供給底層的`QNetworkAccessManager`,實際上是將操作委托給底層`QNetworkAccessManager`進行。 現在我們將?`QNetworkAccessManager`進行了簡單的封裝。下一章我們開始針對 OpenWeatherMap 的 API 進行編碼。
                  <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>

                              哎呀哎呀视频在线观看