qt中的訊號和槽
在圖形介面程式設計中,很多時候我們希望乙個可視物件發生某種變化時通知另乙個或幾個物件,再乙個地說,我們希望任何一類的物件能和其他物件進行通訊。例如,某個數值顯示視窗負責顯示某個滾動條物件的當前數值,當滾動條物件的值發生變化時,我們希望數值顯示視窗能收到來自滾動條物件傳送的「數值改變」的訊號,從而改變自己的顯示數值。
對於類似以上的問題,較早的工具包使用「**」的方式來實現。**是指乙個函式的指標,如果你希望乙個處理函式同志你一些事件,你可以把另乙個函式的指標傳遞給處理函式。處理函式在適當的時候會呼叫**函式。
採用**方式實現物件間的通訊有兩個主要缺點,首先**函式不是型別安全的,我們不能確定處理函式使用了正確的引數來呼叫**函式,第二,**函式和處理函式間的聯絡非常緊密,因為處理函式必須知道要呼叫哪個**函式。
在qt開發環境中,實現物件間的通訊我們有一種稱為「訊號和槽」的機制可以代替**函式。訊號和槽機制用於實現物件間的通訊,是qt的乙個中心特性,恐怕也是qt與其它工具包最不同的地方了。
訊號和槽機制就是:當乙個特定的事件發生時,乙個或幾個被指定的訊號就被發射,槽就是乙個返回值為void的函式,如果存在乙個或幾個槽和該訊號相連線,那在該訊號被發射後,這個(些)槽(函式)就會立刻被執行。
訊號和槽機制是型別安全的,乙個訊號的簽名必須與它的接收槽的簽名相匹配,這樣編譯器就可以幫助我們檢查型別是否匹配。訊號和槽是很寬鬆的聯絡在一起的,乙個發射訊號的物件不用考慮哪個槽會接收這個訊號,接收訊號的槽的所在物件也不知道要連線的訊號是哪個物件發射的。qt的訊號和槽機制可以保證如果你把乙個訊號和乙個槽連線起來後,槽會在正確的時間使用訊號的引數而被呼叫,訊號和槽可以使用任何數量、型別的引數。
qt的視窗部件已經有很多預定義的訊號,也有很多預定義的槽,但我們總是通過繼承來加入我們自己的訊號和自己的槽,這樣我們就可以處理感興趣的訊號了。凡是從qobject類或者它的某個子類繼承的所有類都可以包含訊號和槽。當某個事件發生後,被指定的訊號就會被發射,它不知道也沒有必要知道是否有槽連線了該訊號,這就是資訊封裝。
槽是可以用來接收訊號的正常的物件的成員函式,乙個槽不知道它是否被其它訊號連線。可以把乙個訊號和乙個槽進行單獨連線,這時槽會因為該訊號被發射而被執行;也可以把幾個訊號連線在同乙個槽上,這樣任何乙個訊號被發射都會使得該槽被執行;也可以把乙個訊號和多個槽連線在一起,這樣該訊號一旦被發射,與之相連線的槽都會被馬上執行,但執行的順序不確定,也不可以指定;也可以把乙個訊號和另乙個訊號進行連線,這樣,只要第乙個訊號被發射,第二個訊號立刻就被發射。
下面看看不使用訊號和槽和使用訊號和槽的兩個物件有什麼不同。
不使用訊號和槽的c++物件:
class nosignalclass
int value (void) const
int setvalue (int value)
private:
int _value;
}使用訊號和槽的qt物件:
class usesignalclass
int value (void) const
public slots:
int setvalue (int value)
signals:
void valuechanged (int);
private:
int _value;
}這兩個類有相同的內部狀態,相同的公有方法,但後乙個類卻支援使用訊號和槽的元件程式設計:這個類可以通過發射乙個訊號(valuechanged())來告訴外界它的狀態發生了變化,並且它有乙個槽,可以接收訊號。所有包含訊號和槽的類都必須在它們的宣告中提到q_object。槽要由自己來實現,這裡最好把int setvalue (int value)槽這樣實現:
void usesignalclass::setvalue( int value )
}emit valuechanged(value);這行**是發射乙個訊號valuechanged。
要想使乙個槽在乙個訊號被發射後被執行,要顯示地進行連線:
usesignalclass a,b;
connect(&a, signal(valuechanged(int)), &b, slot(setvalue(int)));
這樣做後,就把物件a的訊號valuechanged和物件b的槽setvalue連線了起來,當a的訊號valuechanged被發射後,物件b的槽setvalue馬上就被執行。
執行以下這句**:
b.setvalue( 10 );
這句被執行後,物件b的valuechanged訊號會被發射,但沒有槽和該訊號相連,所以什麼也沒做,訊號被丟棄。
a.setvalue( 80);
這句被執行後,物件a的valuechanged訊號會被發射,該訊號有槽(物件b的setvalue)相連,所以b.setvalue(int)馬上被執行,且引數為80,所以b.value()的值為80。
如果要解除已經建立好連線的訊號和槽,可以使用disconnect()函式。bool qobject::disconnect ( const qobject * sender, const char * signal,
const object * receiver, const char * member ) [static]
這個函式斷開發射者中的訊號和接收者中的槽函式之間的關聯。有以下三種情況:
1、斷開某個物件與其它物件的任何連線:
disconnect(object, 0, 0, 0);或object->disconnect();
2、斷開某個訊號與其它任何槽的連線:
disconnect(object, signal(signal()), 0, 0);或object->disconnect(signal(signal()));
3、斷開兩個物件之間的任何關聯:
disconnect(object, 0, receiver, 0);或object->disconnect(receiver);
在disconnect函式中0可以用作乙個萬用字元,可分別表示任何訊號、任何接收物件、接收物件中的任何槽函式。但是發射者不能為0,其它三個引數都可以為0。
關鍵字signals指出隨後開始訊號的宣告,這裡signals用的是複數形式而非單數,siganls沒有public、private、protected等屬性,這點不同於slots。另外,signals、slots關鍵字是qt自己定義的,不是c++中的關鍵字。
這個例子說明,採用qt的訊號和槽機制後,物件之間可以在相互不知道的情況下一起工作,只要在最初的時候在他們中間建立了連線。
槽也是普通的c++函式,可以一樣被呼叫,他唯一的特點就是 他們可以被訊號連線。因為槽就是普通的成員函式,它們也和普通的成員函式一樣有訪問許可權,乙個槽的訪問許可權決定了哪些訊號可以和它相連線,而訊號就沒有訪問許可權的概念。
乙個public slots:區包含了任何訊號都可以相連的槽。你生成了許多物件,它們互相並不知道,把它們的訊號和槽連線起來,這樣資訊就可以正確地傳遞,並且就像乙個鐵路模型,把它開啟然後讓它跑起來。
乙個protected slots:區包含了之後這個類和它的子類的訊號才能連線的槽。這就是說這些槽只是類的實現的一部分,而不是它和外界的介面。
乙個private slots:區包含了之後這個類本身的訊號可以連線的槽。這就是說它和這個類是非常緊密的,甚至它的子類都沒有獲得連線權利這樣的信任。
也可以把槽定義為虛函式,這也很有用。
使用訊號和槽機制,要注意以下問題:
1、訊號和槽的機制是非常有效的,但是它不像「真正的」**那樣快。訊號和槽稍微有些慢,這是因為它們所提供的靈活性。但這種損失相對來說是比較小的。但要追求高效率的話,比如在實時系統中就要盡量少用這種機制。
2、訊號和槽機制與普通函式的呼叫一樣,如果使用不當的話,在程式執行時有可能形成死迴圈,所以,在定義槽函式時一定要注意避免間接形成無限迴圈,即在槽中再次發射所接收到的同樣的訊號。
3、如果乙個訊號和多個槽相關聯的話,那當這個訊號被發射時,與之相關聯的槽的執行順序將是髓機的,且順序不能指定。
4、巨集定義不能用在signal和slot的引數中。
5、建構函式不能用在signals和slots宣告區域內。
6、函式指標不能作為訊號或槽的引數。
7、訊號和槽不能有預設引數值。
8、訊號和槽不能攜帶模板類引數。
9、巢狀的類不能位於訊號和槽區域內,也不能有訊號或者槽。
10、友元宣告不能位於訊號和槽的宣告區域內。
Qt訊號和槽
qt將訊號和槽關聯起來的connect使用時需要注意帶相應的引數,否則會出現訊號發出後不能呼叫槽的問題,例子如下 發出訊號的宣告 signals void receiveddata uchar dat,uint len 接收訊號的槽宣告 private slots void getdata ucha...
Qt 訊號和槽
函式原型 qobject connect const qobject sender,const char signal,const qobject receiver,const char method,qt connectiontype type qt autoconnection 通常使用的con...
QT訊號和槽
qt訊號和槽 訊號和槽是一種高階介面,應用於物件之間的通訊,它是 qt 的核心特性。要正確的處理訊號和槽,必須借助乙個稱為 moc meta object compiler 的 qt 工具,該工具是乙個 c 預處理程式,它為高層次的事件處理自動生成所需要的附加 訊號和槽能攜帶任意數量和任意型別的引數...