信號(hào)槽機(jī)制是 Qt 編程的基礎(chǔ)。通過(guò)信號(hào)槽,能夠使 Qt 各組件在不知道對(duì)方的情形下能夠相互通訊。這就將類(lèi)之間的關(guān)系做了最大程度的解耦。
槽函數(shù)和普通的 C++ 成員函數(shù)沒(méi)有很大的區(qū)別。它們也可以使 virtual 的;可以被重寫(xiě);可以使public、protected 或者 private 的;可以由其它的 C++ 函數(shù)調(diào)用;參數(shù)可以是任何類(lèi)型的。如果要說(shuō)區(qū)別,那就是,槽函數(shù)可以和一個(gè)信號(hào)相連接,當(dāng)這個(gè)信號(hào)發(fā)生時(shí),它可以被自動(dòng)調(diào)用。
connect()語(yǔ)句的原型類(lèi)似于:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
這里,sender 和 receiver 都是 QObject 類(lèi)型的,singal 和 slot 都是沒(méi)有參數(shù)名稱(chēng)的函數(shù)簽名。SINGAL()和SLOT()宏用于把參數(shù)轉(zhuǎn)換成字符串。
深入的說(shuō),信號(hào)槽還有更多可能的用法,如下所示。
一個(gè)信號(hào)可以和多個(gè)槽相連:
connect(slider, SIGNAL(valueChanged(int)),
spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(updateStatusBarIndicator(int)));
注意,如果是這種情況,這些槽會(huì)一個(gè)接一個(gè)的被調(diào)用,但是它們的調(diào)用順序是不確定的。
多個(gè)信號(hào)可以連接到一個(gè)槽:
connect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),
this, SLOT(handleMathError()));
這是說(shuō),只要任意一個(gè)信號(hào)發(fā)出,這個(gè)槽就會(huì)被調(diào)用。
一個(gè)信號(hào)可以連接到另外的一個(gè)信號(hào):
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SIGNAL(updateRecord(const QString &)));
這是說(shuō),當(dāng)?shù)谝粋€(gè)信號(hào)發(fā)出時(shí),第二個(gè)信號(hào)被發(fā)出。除此之外,這種信號(hào)-信號(hào)的形式和信號(hào)-槽的形式?jīng)]有什么區(qū)別。
槽可以被取消鏈接:
disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
這種情況并不經(jīng)常出現(xiàn),因?yàn)楫?dāng)一個(gè)對(duì)象 delete 之后,Qt 自動(dòng)取消所有連接到這個(gè)對(duì)象上面的槽。
為了正確的連接信號(hào)槽,信號(hào)和槽的參數(shù)個(gè)數(shù)、類(lèi)型以及出現(xiàn)的順序都必須相同,例如:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(processReply(int, const QString &)));
這里有一種例外情況,如果信號(hào)的參數(shù)多于槽的參數(shù),那么這個(gè)參數(shù)之后的那些參數(shù)都會(huì)被忽略掉,例如:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int)));
這里,const QString &這個(gè)參數(shù)就會(huì)被槽忽略掉。
如果信號(hào)槽的參數(shù)不相容,或者是信號(hào)或槽有一個(gè)不存在,或者在信號(hào)槽的連接中出現(xiàn)了參數(shù)名字,在Debug 模式下編譯的時(shí)候,Qt 都會(huì)很智能的給出警告。
在這之前,我們僅僅在 widgets 中使用到了信號(hào)槽,但是,注意到 connect()函數(shù)其實(shí)是在 QObject 中實(shí)現(xiàn)的,并不局限于 GUI,因此,只要我們繼承 QObject 類(lèi),就可以使用信號(hào)槽機(jī)制了:
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;
};
在使用時(shí),我們給出下面的代碼:
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
這樣,當(dāng) setSalary()調(diào)用的時(shí)候,就會(huì)發(fā)出 salaryChanged()信號(hào)。注意這里的 if 判斷,這是避免遞歸的方式!還記得前面提到的循環(huán)連接嗎?如果沒(méi)有 if,當(dāng)出現(xiàn)了循環(huán)連接的時(shí)候就會(huì)產(chǎn)生無(wú)限遞歸。
本文出自 “豆子空間” 博客,請(qǐng)務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/194031