1) 信號的定義必須在signals:保留字下,並且不需要實現
2)槽的定義必須在slots:保留字下,需要實現
3)信號和槽通過QObject::connect函數連接
4)當信號被觸發時,槽函數被調用
需要注意的是:
1)信號和槽,是QT的拓展,所以實現信號和槽的類,必須是QObject的子類
2)實現信號和槽的類,必須以宏Q_OBJECT開始
3)連接信號和槽,要用到SIGNAL和SLOT宏,轉換函數為字符串
4)一個信號可以和多個槽連接,槽函數調用的順序是不確定的
5)多個信號可以同時連接一個槽
6)信號可以連接信號,形成信號傳導
7) 當信號與槽函數的參數數量相同時,它們參數類型要完全一致。
當信號的參數與槽函數的參數數量不同時,只能是信號的參數數量多於槽函數的參數數量,且前面相同數量的參數類型應一致,信號中多余的參數會被忽略。
8)信號和槽都可以重載
9)信號和槽都可以有默認參數
10)槽函數可以像普通函數一樣被調用
11)在槽函數中,調用sender可以獲得信號調用者
總結下:
一個類:QObject信號和槽都是這個類的子類
三個宏:Q_OBJECT SIGNAL SLOT
三個保留字:signals, slots, emit
在 Qt 5 中,QObject::connect()有五個重載:
1 //第一個,sender 類型是const QObject *,signal 的類型是const char *,receiver 類型是const QObject *,slot 類型是const char *。這個函數將 signal 和 slot 作為字符串處理 2 QMetaObject::Connection connect(const QObject *, const char *, 3 const QObject *, const char *, 4 Qt::ConnectionType); 5 6 //第二個,sender 和 receiver 同樣是const QObject *,但是 signal 和 slot 都是const QMetaMethod & 7 QMetaObject::Connection connect(const QObject *, const QMetaMethod &, 8 const QObject *, const QMetaMethod &, 9 Qt::ConnectionType); 10 11 //第三個,sender 同樣是const QObject *,signal 和 slot 同樣是const char *,但是卻缺少了 receiver。這個函數其實是將 this 指針作為 receiver 12 QMetaObject::Connection connect(const QObject *, const char *, 13 const char *, 14 Qt::ConnectionType) const; 15 16 //第四個,sender 和 receiver 也都存在,都是const QObject *,但是 signal 和 slot 類型則是PointerToMemberFunction。看這個名字就應該知道,這是指向成員函數的指針 17 QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, 18 const QObject *, PointerToMemberFunction, 19 Qt::ConnectionType) 20 21 //第五個,前面兩個參數沒有什么不同,最后一個參數是Functor類型。這個類型可以接受 static 函數、全局函數以及 Lambda 表達式 22 QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, 23 Functor);
注意:用lambda表達式在.pro中加入 CONFIG += C++11
QT4我們使用了SIGNAL和SLOT這兩個宏,將兩個函數名轉換成了字符串。注意,即使quit()是QApplication的 static 函數,也必須傳入一個對象指針。這也是 Qt 4 的信號槽語法的局限之處。另外,注意到connect()函數的 signal 和 slot 都是接受字符串,因此,不能將全局函數或者 Lambda 表達式傳入connect()。一旦出現連接不成功的情況,Qt 4 是沒有編譯錯誤的(因為一切都是字符串,編譯期是不檢查字符串是否匹配),而是在運行時給出錯誤。這無疑會增加程序的不穩定性。
eg:

1 #include <QApplication> 2 #include <QWidget> 3 #include <QHBoxLayout> 4 #include <QSlider> 5 #include <QSpinBox> 6 7 8 int main(int argc,char **argv) 9 { 10 QApplication app(argc,argv); 11 12 QWidget w; 13 w.setWindowTitle("Enter your age"); 14 15 QSpinBox *spinbox = new QSpinBox(&w); 16 QSlider *slider = new QSlider(Qt::Horizontal,&w); 17 spinbox->setRange(0,130); 18 slider->setRange(0,130); 19 20 /* 21 //QT4的寫法,使用SIGNAL和SLOT, 22 QObject::connect(slider,SIGNAL(valueChanged(int)),spinbox,SLOT(setValue(int))); 23 QObject::connect(spinbox,SIGNAL(valueChanged(int)),slider,SLOT(setValue(int))); 24 */ 25 26 //QT5的寫法,用指向成員函數的指針 27 QObject::connect(slider,&QSlider::valueChanged,spinbox,&QSpinBox::setValue); 28 29 //如果不加下面一行會報錯,原因是QSpinBox的確有兩個信號:void valueChanged(int)和void valueChanged(const QString &) 30 //使用 Qt 4 的SIGNAL和SLOT宏,因為這兩個宏已經指定了參數信息,所以不存在這個問題,解決方法使用函數指針顯式指定使用哪一個信號 31 void(QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged; 32 QObject::connect(spinbox,spinBoxSignal,slider,&QSlider::setValue); 33 34 35 spinbox->setValue(44); 36 37 QHBoxLayout *layout = new QHBoxLayout; 38 layout->addWidget(spinbox); 39 layout->addWidget(slider); 40 w.setLayout(layout); 41 w.show(); 42 43 return app.exec(); 44 }
