訊號和槽是Qt編程的一個重要部分。這個機制可以在對象之間彼此並不瞭解的情況下將它們的行為聯絡起來。在前幾個常式中,我們已經串連了訊號和槽,聲明了控制項自己的訊號和槽,並實現了槽函數,發送了訊號。現在來更深入瞭解這個機制。
槽和普通的c++成員函數很像。它們可以是虛函數(virtual),也可被重載(overload),可以是公有的(public),保護的(protective),也可是私人的(private),它們可以象任何c++成員函數一樣被調用,可以傳遞任何類型的參數。不同在於一個槽函數能和一個訊號相串連,只要訊號發出了,這個槽函數就會自動被調用。
connect函數文法如下:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
sender和receiver是QObject對象指標,signal和slot是不帶參數的函數原型。SIGNALE()和SLOT()宏的作用是把他們轉換成字串。
在目前有的例子中,我們已經串連了不同的訊號和槽。實際使用中還要考慮如下一些規則:
1、一個訊號可以串連到多個槽:
connect(slider, SIGNAL(valueChanged(int)),spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChanged(int)),this, SLOT(updateStatusBarIndicator(int)));
當訊號發出後,槽函數都會被調用,但是調用的順序是隨機的,不確定的。
2、多個訊號可以串連到一個槽
connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),this, SLOT(handleMathError()));
任何一個訊號發出,槽函數都會執行。
3、一個訊號可以和另一個訊號相連
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SIGNAL(updateRecord(const QString &)));
第一個訊號發出後,第二個訊號也同時發送。除此之外,訊號與訊號串連上和訊號和槽串連相同。
4、串連可以被刪除
disconnect(lcd, SIGNAL(overflow()),this, SLOT(handleMathError()));
這個函數很少使用,一個對象刪除後,Qt自動刪除這個對象的所有串連。
訊號和槽函數必須有著相同的參數類型,這樣訊號和槽函數才能成功串連:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),this, SLOT(processReply(int, const QString &)));
如果訊號裡的參數個數多於槽函數的參數,多餘的參數被忽略:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),this, SLOT(checkErrorCode(int)));
如果參速類型不符,或者訊號和槽不存在,在debug狀態時,Qt會在運行期間給出警告。如果訊號和槽串連時包含了參數的名字,Qt將會給出警告。
以前我們列舉的例子中都是控制項的訊號和槽。但是訊號和槽機制在QObject中就實現了,可以實現在任何從QObject繼承的子類中。
class Employee : public QObject
{
Q_OBJECT
public:
Employee() { mySalary = 0; }
int salary() const { return mySalary; }
public slots:
void setSalary(int newSalary);
signals:
void salaryChanged(int newSalary);
private:
int mySalary;
};
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
注意,只有newSalary != mySalary時才發出salary-Changed()訊號,這樣避免了死迴圈的出現。