<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國際加速解決方案。 廣告
                #(4)信號槽 信號槽是 Qt 框架引以為豪的機制之一。熟練使用和理解信號槽,能夠設計出解耦的非常漂亮的程序,有利于增強我們的技術設計能力。 所謂信號槽,實際就是觀察者模式。當某個事件發生之后,比如,按鈕檢測到自己被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,類似廣播。如果有對象對這個信號感興趣,它就會使用連接(connect)函數,意思是,用自己的一個函數(成為槽(slot))來處理這個信號。也就是說,當信號發出時,被連接的槽函數會自動被回調。這就類似觀察者模式:當發生了感興趣的事件,某一個操作就會被自動觸發。*(這里提一句,Qt 的信號槽使用了額外的處理來實現,并不是 GoF 經典的觀察者模式的實現方式。)* 為了體驗一下信號槽的使用,我們以一段簡單的代碼說明: ~~~ // !!! Qt 5 #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Quit"); QObject::connect(&button, &QPushButton::clicked, &QApplication::quit); button.show(); return app.exec(); } ~~~ 這里再次強調,我們的代碼是以 Qt 5 為主線,這意味著,有的代碼放在 Qt 4 上是不能編譯的。因此,豆子會在每一段代碼的第一行添加注釋,用以表明該段代碼是使用 Qt 5 還是 Qt 4 進行編譯。讀者在測試代碼的時候,需要自行選擇相應的 Qt 版本。 我們按照前面文章中介紹的在 Qt Creator 中創建工程的方法創建好工程,然后將`main()`函數修改為上面的代碼。點擊運行,我們會看到一個按鈕,上面有“Quit”字樣。點擊按鈕,程序退出。 按鈕在 Qt 中被稱為`QPushButton`。對它的創建和顯示,同前文類似,這里不做過多的講解。我們這里要仔細分析`QObject::connect()`這個函數。 在 Qt 5 中,`QObject::connect()`有五個重載: ~~~ QMetaObject::Connection connect(const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType); QMetaObject::Connection connect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &, Qt::ConnectionType); QMetaObject::Connection connect(const QObject *, const char *, const char *, Qt::ConnectionType) const; QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, const QObject *, PointerToMemberFunction, Qt::ConnectionType) QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, Functor); ~~~ 這五個重載的返回值都是`QMetaObject::Connection`,現在我們不去關心這個返回值。下面我們先來看看`connect()`函數最常用的一般形式: ~~~ // !!! Qt 5 connect(sender, signal, receiver, slot); ~~~ 這是我們最常用的形式。`connect()`一般會使用前面四個參數,第一個是發出信號的對象,第二個是發送對象發出的信號,第三個是接收信號的對象,第四個是接收對象在接收到信號之后所需要調用的函數。也就是說,當 sender 發出了 signal 信號之后,會自動調用 receiver 的 slot 函數。 這是最常用的形式,我們可以套用這個形式去分析上面給出的五個重載。第一個,sender 類型是`const QObject *`,signal 的類型是`const char *`,receiver 類型是`const QObject *`,slot 類型是`const char *`。這個函數將 signal 和 slot 作為字符串處理。第二個,sender 和 receiver 同樣是`const QObject *`,但是 signal 和 slot 都是`const QMetaMethod &`。我們可以將每個函數看做是`QMetaMethod`的子類。因此,這種寫法可以使用`QMetaMethod`進行類型比對。第三個,sender 同樣是`const QObject *`,signal 和 slot 同樣是`const char *`,但是卻缺少了 receiver。這個函數其實是將 this 指針作為 receiver。第四個,sender 和 receiver 也都存在,都是`const QObject *`,但是 signal 和 slot 類型則是`PointerToMemberFunction`。看這個名字就應該知道,這是指向成員函數的指針。第五個,前面兩個參數沒有什么不同,最后一個參數是`Functor`類型。這個類型可以接受 static 函數、全局函數以及 Lambda 表達式。 由此我們可以看出,`connect()`函數,sender 和 receiver 沒有什么區別,都是`QObject`指針;主要是 signal 和 slot 形式的區別。具體到我們的示例,我們的`connect()`函數顯然是使用的第五個重載,最后一個參數是`QApplication`的 static 函數`quit()`。也就是說,當我們的 button 發出了`clicked()`信號時,會調用`QApplication`的`quit()`函數,使程序退出。 信號槽要求信號和槽的參數一致,所謂一致,是參數類型一致。如果不一致,允許的情況是,槽函數的參數可以比信號的少,即便如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是因為,你可以在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),但是不能說信號根本沒有這個數據,你就要在槽函數中使用(就是槽函數的參數比信號的多,這是不允許的)。 如果信號槽不符合,或者根本找不到這個信號或者槽函數的話,比如我們改成: ~~~ QObject::connect(&button, &QPushButton::clicked, &QApplication::quit2); ~~~ 由于 QApplication 沒有 quit2 這樣的函數的,因此在編譯時,會有編譯錯誤: ~~~ 'quit2' is not a member of QApplication ~~~ 這樣,使用成員函數指針,我們就不會擔心在編寫信號槽的時候會出現函數錯誤。 借助 Qt 5 的信號槽語法,我們可以將一個對象的信號連接到 Lambda 表達式,例如: ~~~ // !!! Qt 5 #include <QApplication> #include <QPushButton> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Quit"); QObject::connect(&button, &QPushButton::clicked, [](bool) { qDebug() << "You clicked me!"; }); button.show(); return app.exec(); } ~~~ 注意這里的 Lambda 表達式接收一個 bool 參數,這是因為`QPushButton`的`clicked()`信號實際上是有一個參數的。Lambda 表達式中的`qDebug()`類似于`cout`,將后面的字符串打印到標準輸出。如果要編譯上面的代碼,你需要在 pro 文件中添加這么一句: ~~~ QMAKE_CXXFLAGS += -std=c++0x ~~~ 然后正常編譯即可。 Qt 4 的信號槽同 Qt 5 類似。在 Qt 4 的 QObject 中,有三個不同的`connect()`重載: ~~~ bool connect(const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType); bool connect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &, Qt::ConnectionType); bool connect(const QObject *, const char *, const char *, Qt::ConnectionType) const ~~~ 除了返回值,Qt 4 的`connect()`函數與 Qt 5 最大的區別在于,Qt 4 的 signal 和 slot 只有`const char *`這么一種形式。如果我們將上面的代碼修改為 Qt 4 的,則應該是這樣的: ~~~ // !!! Qt 4 #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Quit"); QObject::connect(&button, SIGNAL(clicked()), &app, SLOT(quit())); button.show(); return app.exec(); } ~~~ 我們使用了`SIGNAL`和`SLOT`這兩個宏,將兩個函數名轉換成了字符串。注意,即使`quit()`是`QApplication`的 static 函數,也必須傳入一個對象指針。這也是 Qt 4 的信號槽語法的局限之處。另外,注意到`connect()`函數的 signal 和 slot 都是接受字符串,因此,不能將全局函數或者 Lambda 表達式傳入`connect()`。一旦出現連接不成功的情況,Qt 4 是沒有編譯錯誤的(因為一切都是字符串,編譯期是不檢查字符串是否匹配),而是在運行時給出錯誤。這無疑會增加程序的不穩定性。 信號槽機制是 Qt 的最大特性之一。這次我們只是初略了解了信號槽,知道了如何使用`connect()`函數進行信號槽的連接。在后面的內容中,我們將進一步介紹信號槽,了解如何設計自己的信號槽等等。
                  <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>

                              哎呀哎呀视频在线观看