QT——信號和槽機制

        信號和槽用於兩個對象之間的通訊,信號和槽機制是Qt的核心特徵,也是Qt不一樣於其餘開發框架的最突出的特徵。編程

        信號和槽機制的特點和優越性:
安全

            1. 信號和槽機制是類型安全的,相關聯的信號和槽的參數必須匹配;
app

            2. 信號和槽是鬆耦合的,信號發送者不知道也不須要知道接受者的信息;框架

            3. 信號和槽可使用任意類型的任意數量的參數。函數

        雖然信號和槽機制提供了高度的靈活性,但就其性能而言,仍是慢於回調機制的。
工具

    /*
    信號與槽機制是比較靈活的,但有些侷限性咱們必須瞭解,這樣在實際的使用過程當中作到有的放矢,
    避免產生一些錯誤。下面就介紹一下這方面的狀況。
1.信號與槽的效率是很是高的,可是同真正的回調函數比較起來,因爲增長了靈活性,所以在速度上仍是有所損失,
    固然這種損失相對來講是比較小的,經過在一臺i586-133的機器上測試是10微秒(運行Linux),
    可見這種機制所提供的簡潔性、靈活性仍是值得的。
    但若是咱們要追求高效率的話,好比在實時系統中就要儘量的少用這種機制。
2.信號與槽機制與普通函數的調用同樣,若是使用不當的話,在程序執行時也有可能產生死循環。
    所以,在定義槽函數時必定要注意避免間接造成無限循環,即在槽中再次發射所接收到的一樣信號。
    例如,在前面給出的例子中若是在mySlot()槽函數中加上語句emit mySignal()便可造成死循環。
3.若是一個信號與多個槽相聯繫的話,那麼,當這個信號被髮射時,與之相關的槽被激活的順序將是隨機的。
4. 宏定義不能用在signal和slot的參數中。
    既然moc工具不擴展#define,所以,在signals和slots中攜帶參數的宏就不能正確地工做,若是不帶參數是能夠的。
    例如,下面的例子中將帶有參數的宏SIGNEDNESS(a)做爲信號的參數是不合語法的:
    */

        在GUI編程中,當改變了一個部件時,總但願其餘部件也能瞭解到該變化。更通常來講,咱們但願任何對象均可以和其餘對象進行通訊。性能

        當一個特殊的事情發生時即可以發射一個信號,好比按鈕被單擊;而槽就是一個函數,它在信號發射後被調用,來響應這個信號。
測試

        在Qt的部件類中已經定義了一些信號和槽,可是更多的作法是子類化這個部件,而後添加本身的信號和槽來實現想要的功能。
ui

        一個信號對應一個槽。其實,一個信號能夠關聯到多個槽上,多個信號也能夠關聯到同一個槽上,甚至,一個信號還能夠關聯到另外一個信號上。若是存在多個槽與某個信號相關聯,那麼,當這個信號被髮射時,這些槽將會一個接一個地執行,可是它們執行的順序是隨機的,沒法指定它們的執行順序。
this


一個簡單的例子來進一步講解信號和槽的相關知識,這個例子實現的效果是:在主界面中建立一個對話框,在這個對話框中能夠輸入數值,當按下肯定按鈕時關閉對話框而且將輸入的數值經過信號發射出去,而在主界面中接收該信號而且顯示數值。

  1. 子類mydialog.h中聲明一個信號:

    signals:

        void dlgReturn(int);                  // 自定義的信號

    聲明一個信號要使用signals關鍵字,在signals前面不能使用public、private和protected等限定符,由於只有定義該信號的類及其子類才能夠發射該信號。並且信號只用聲明,不須要也不能對它進行定義實現。還要注意,信號沒有返回值,只能是void類型的。

  2. 在mydialog.ui的「肯定」按鈕clicked()槽函數中添加:

    void MyDialog::on_pushButton_clicked()   // 肯定按鈕

    {

       int value = ui->spinBox->value();    // 獲取輸入的數值

       emit  dlgReturn(value);               // 發射信號

       close();                             // 關閉對話框

    }

  3.  而後到widget.h文件中添加自定義槽的聲明:

     private slots:

        void showValue(int value);

    聲明一個槽須要使用slots關鍵字。一個槽能夠是private、public或者protected類型的,槽也能夠被聲明爲虛函數,這與普通的成員函數是同樣的,也能夠像調用一個普通函數同樣來調用槽。槽的最大特色就是能夠和信號關聯。

  4. widget.cpp的構造函數中添加:

    MyDialog *dlg = new MyDialog(this);

    // 將對話框中的自定義信號與主界面中的自定義槽進行關聯

    connect(dlg,SIGNAL(dlgReturn(int)),this,SLOT(showValue(int)));

    dlg->show();

  5. widget.cpp 中實現自定義槽函數:

    void Widget::showValue(int value)         // 自定義槽

    {

       ui->label->setText(tr("獲取的值是:%1").arg(value));

    }

  6. 運行程序


connect()函數原型:

//connect()函數,這個函數的原型以下:
bool QObject::connect ( const QObject *sender, const char * signal, const QObject * receiver, const char * method,Qt::ConnectionType type = Qt::AutoConnection )
/*
它的第一個參數爲發送信號的對象,例如這裏的dlg;
第二個參數是要發送的信號,這裏是SIGNAL(dlgReturn(int));
第三個參數是接收信號的對象,這裏是this,代表是本部件,即Widget,當這個參數爲this時,也能夠將這個參數省略掉,
    由於connect()函數還有另一個重載形式,該參數默認爲this;
第四個參數是要執行的槽,這裏是SLOT(showValue(int))。對於信號和槽,必須使用SIGNAL()和SLOT()宏,它們能夠將其參數轉化爲const char* 類型。
connect()函數的返回值爲bool類型,當關聯成功時返回true。
還要注意,在調用這個函數時信號和槽的參數只能有類型,不能有變量,例如寫成SLOT(showValue(int value))是不對的。
對於信號和槽的參數問題,基本原則是信號中的參數類型要和槽中的參數類型相對應,並且信號中的參數能夠多於槽中的參數,可是不能反過來,若是信號中有多餘的參數,那麼它們將被忽略。
下面介紹一下connect()函數的最後一個參數,它代表了關聯的方式,其默認值是Qt::AutoConnection,
這裏還有其餘幾個選擇,在編程中通常使用默認值,
例如這裏,在MyDialog類中使用emit發射了信號以後,就會執行槽,只有等槽執行完了之後,纔會執行emit語句後面的代碼。
你們也能夠將這個參數改成Qt::QueuedConnection,這樣在執行完emit語句後便會當即執行其後面的代碼,而無論槽是否已經執行。
當再也不使用這個關聯時,還可使用disconnect()函數來斷開關聯。
*/


注意:

        須要繼承自QObject或其子類;

        在類聲明的最開始處添加Q_OBJECT宏;

        槽中的參數的類型要和信號的參數的類型相對應,且不能比信號的參數多;

        信號只用聲明,沒有定義,且返回值爲void類型。

信號和槽的高級應用:

         有時咱們但願得到信號發送者的信息,在Qt中提供了QObject::sender()函數來返回發送該信號的對象的指針。可是若是有多個信號關聯到了同一個槽上,而在該槽中須要對每個信號進行不一樣的處理,使用上面的方法就很麻煩了。對於這種狀況,即可以使用QSignalMapper類。QSignalMapper能夠被叫作信號映射器,它能夠實現對多個相同部件的相同信號進行映射,爲其添加字符串或者數值參數,而後再發射出去。

相關文章
相關標籤/搜索