Linux下應用程式開發:QT的訊號與槽機制(轉)
Linux下應用程式開發:QT的訊號與槽機制(轉)[@more@] 訊號與槽作為QT的核心機制在QT程式設計中有著廣泛的應用,本文介紹了訊號與槽的一些基本概念、元物件工具以及在實際使用過程中應注意的一些問題。
QT是一個跨平臺的C++ GUI應用構架,它提供了豐富的視窗部件集,具有物件導向、易於擴充套件、真正的元件程式設計等特點,更為引人注目的是目前Linux上最為流行的KDE桌面環境就是建立在QT庫的基礎之上。QT支援下列平臺:MS/WINDOWS-95、98、NT和2000;UNIX/X11-Linux、Sun Solaris、HP-UX、Digital Unix、IBM AIX、SGI IRIX;EMBEDDED-支援framebuffer的Linux平臺。伴隨著KDE的快速發展和普及,QT很可能成為Linux視窗平臺上進行軟體開發時的GUI首選。
一、概述
訊號和槽機制是QT的核心機制,要精通QT程式設計就必須對訊號和槽有所瞭解。訊號和槽是一種高階介面,應用於物件之間的通訊,它是QT的核心特性,也是QT區別於其它工具包的重要地方。訊號和槽是QT自行定義的一種通訊機制,它獨立於標準的C/C++語言,因此要正確的處理訊號和槽,必須藉助一個稱為moc(Meta Object Compiler)的QT工具,該工具是一個C++預處理程式,它為高層次的事件處理自動生成所需要的附加程式碼。
在我們所熟知的很多GUI工具包中,視窗小部件(widget)都有一個回撥函式用於響應它們能觸發的每個動作,這個回撥函式通常是一個指向某個函式的指標。但是,在QT中訊號和槽取代了這些凌亂的函式指標,使得我們編寫這些通訊程式更為簡潔明瞭。 訊號和槽能攜帶任意數量和任意型別的引數,他們是型別完全安全的,不會像回撥函式那樣產生core dumps。
所有從QObject或其子類(例如Qwidget)派生的類都能夠包含訊號和槽。當物件改變其狀態時,訊號就由該物件發射(emit)出去,這就是物件所要做的全部事情,它不知道另一端是誰在接收這個訊號。這就是真正的資訊封裝,它確保物件被當作一個真正的軟體元件來使用。槽用於接收訊號,但它們是普通的物件成員函式。一個槽並不知道是否有任何訊號與自己相連線。而且,物件並不瞭解具體的通訊機制。
你可以將很多訊號與單個的槽進行連線,也可以將單個的訊號與很多的槽進行連線,甚至於將一個訊號與另外一個訊號相連線也是可能的,這時無論第一個訊號什麼時候發射系統都將立刻發射第二個訊號。總之,訊號與槽構造了一個強大的部件程式設計機制。
二、訊號
當某個訊號對其客戶或所有者發生的內部狀態發生改變,訊號被一個物件發射。只有 定義過這個訊號的類及其派生類能夠發射這個訊號。當一個訊號被髮射時,與其相關聯的槽將被立刻執行,就象一個正常的函式呼叫一樣。訊號-槽機制完全獨立於任何GUI事件迴圈。只有當所有的槽返回以後發射函式(emit)才返回。 如果存在多個槽與某個訊號相關聯,那麼,當這個訊號被髮射時,這些槽將會一個接一個地 執行,但是它們執行的順序將會是隨機的、不確定的,我們不能人為地指定哪個先執行、哪 個後執行。
訊號的宣告是在標頭檔案中進行的,QT的signals關鍵字指出進入了訊號宣告區,隨後即可 宣告自己的訊號。例如,下面定義了三個訊號:
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);
在上面的定義中,signals是QT的關鍵字,而非C/C++的。接下來的一行void mySignal() 定義了訊號mySignal,這個訊號沒有攜帶引數;接下來的一行void mySignal(int x)定義 了重名訊號mySignal,但是它攜帶一個整形引數,這有點類似於C++中的虛擬函式。從形式上 講訊號的宣告與普通的C++函式是一樣的,但是訊號卻沒有函式體定義,另外,訊號的返回 型別都是void,不要指望能從訊號返回什麼有用資訊。
訊號由moc自動產生,它們不應該在.cpp檔案中實現。
三、槽
槽是普通的C++成員函式,可以被正常呼叫,它們唯一的特殊性就是很多訊號可以與其相關聯。當與其關聯的訊號被髮射時,這個槽就會被呼叫。槽可以有引數,但槽的引數不能有預設值。
既然槽是普通的成員函式,因此與其它的函式一樣,它們也有存取許可權。槽的存取許可權決定了誰能夠與其相關聯。同普通的C++成員函式一樣,槽函式也分為三種型別,即public slots、private slots和protected slots。
public slots:在這個區內宣告的槽意味著任何物件都可將訊號與之相連線。這對於元件程式設計非常有用,你可以建立彼此互不瞭解的物件,將它們的訊號與槽進行連線以便資訊能夠正確的傳遞。
protected slots:在這個區內宣告的槽意味著當前類及其子類可以將訊號與之相連線。這適用於那些槽,它們是類實現的一部分,但是其介面介面卻面向外部。
private slots:在這個區內宣告的槽意味著只有類自己可以將訊號與之相連線。這適用於聯絡非常緊密的類。
槽也能夠宣告為虛擬函式,這也是非常有用的。
槽的宣告也是在標頭檔案中進行的。例如,下面宣告瞭三個槽:
public slots:
void mySlot();
void mySlot(int x);
void mySignalParam(int x,int y);
四、訊號與槽的關聯
透過呼叫QObject物件的connect函式來將某個物件的訊號與另外一個物件的槽函式相關聯,這樣當發射者發射訊號時,接收者的槽函式將被呼叫。該函式的定義如下:
bool QObject::connect ( const QObject * sender, const char * signal,
const QObject * receiver, const char * member ) [static]
這個函式的作用就是將發射者sender物件中的訊號signal與接收者receiver中的member槽函式聯絡起來。當指定訊號signal時必須使用QT的宏SIGNAL(),當指定槽函式時必須使用宏SLOT()。如果發射者與接收者屬於同一個物件的話,那麼在connect呼叫中接收者引數可以省略。
例如,下面定義了兩個物件:標籤物件label和捲軸物件scroll,並將valueChanged()訊號與標籤物件的setNum()相關聯,另外訊號還攜帶了一個整形引數,這樣標籤總是顯示捲軸所處位置的值。
QLabel *label = new QLabel;
QScrollBar *scroll = new QScrollBar;
QObject::connect( scroll, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)) );
一個訊號甚至能夠與另一個訊號相關聯,看下面的例子:
class MyWidget : public QWidget
{
public:
MyWidget();
...
signals:
void aSignal();
...
private:
...
QPushButton *aButton;
};
MyWidget::MyWidget()
{
aButton = new QPushButton( this );
connect( aButton, SIGNAL(clicked()), SIGNAL(aSignal()) );
}
在上面的建構函式中,MyWidget建立了一個私有的按鈕aButton,按鈕的單擊事件產生的訊號clicked()與另外一個訊號aSignal()進行了關聯。這樣一來,當訊號clicked()被髮射時,訊號aSignal()也接著被髮射。當然,你也可以直接將單擊事件與某個私有的槽函式相關聯,然後在槽中發射aSignal()訊號,這樣的話似乎有點多餘。
當訊號與槽沒有必要繼續保持關聯時,我們可以使用disconnect函式來斷開連線。其定義如下:
bool QObject::disconnect ( const QObject * sender, const char * signal,
const Object * receiver, const char * member ) [static]
這個函式斷開發射者中的訊號與接收者中的槽函式之間的關聯。
有三種情況必須使用disconnect()函式:
斷開與某個物件相關聯的任何物件。這似乎有點不可理解,事實上,當我們在某個物件中定義了一個或者多個訊號,這些訊號與另外若干個物件中的槽相關聯,如果我們要切斷這些關聯的話,就可以利用這個方法,非常之簡潔。
disconnect( myObject, 0, 0, 0 )
或者
myObject->disconnect()
斷開與某個特定訊號的任何關聯。
disconnect( myObject, SIGNAL(mySignal()), 0, 0 )
或者
myObject->disconnect( SIGNAL(mySignal()) )
斷開兩個物件之間的關聯。
disconnect( myObject, 0, myReceiver, 0 )
或者
myObject->disconnect( myReceiver )
在disconnect函式中0可以用作一個萬用字元,分別表示任何訊號、任何接收物件、接收物件中的任何槽函式。但是發射者sender不能為0,其它三個引數的值可以等於0。
五、元物件工具
元物件編譯器moc(meta object compiler)對C++檔案中的類宣告進行分析併產生用於初始化元物件的C++程式碼,元物件包含全部訊號和槽的名字以及指向這些函式的指標。
moc讀C++原始檔,如果發現有Q_OBJECT宏宣告的類,它就會生成另外一個C++原始檔,這個新生成的檔案中包含有該類的元物件程式碼。例如,假設我們有一個標頭檔案mysignal.h,在這個檔案中包含有訊號或槽的宣告,那麼在編譯之前 moc 工具就會根據該檔案自動生成一個名為mysignal.moc.h的C++原始檔並將其提交給編譯器;類似地,對應於mysignal.cpp檔案moc工具將自動生成一個名為mysignal.moc.cpp檔案提交給編譯器。
元物件程式碼是signal/slot機制所必須的。用moc產生的C++原始檔必須與類實現一起進行編譯和連線,或者用#
QT是一個跨平臺的C++ GUI應用構架,它提供了豐富的視窗部件集,具有物件導向、易於擴充套件、真正的元件程式設計等特點,更為引人注目的是目前Linux上最為流行的KDE桌面環境就是建立在QT庫的基礎之上。QT支援下列平臺:MS/WINDOWS-95、98、NT和2000;UNIX/X11-Linux、Sun Solaris、HP-UX、Digital Unix、IBM AIX、SGI IRIX;EMBEDDED-支援framebuffer的Linux平臺。伴隨著KDE的快速發展和普及,QT很可能成為Linux視窗平臺上進行軟體開發時的GUI首選。
一、概述
訊號和槽機制是QT的核心機制,要精通QT程式設計就必須對訊號和槽有所瞭解。訊號和槽是一種高階介面,應用於物件之間的通訊,它是QT的核心特性,也是QT區別於其它工具包的重要地方。訊號和槽是QT自行定義的一種通訊機制,它獨立於標準的C/C++語言,因此要正確的處理訊號和槽,必須藉助一個稱為moc(Meta Object Compiler)的QT工具,該工具是一個C++預處理程式,它為高層次的事件處理自動生成所需要的附加程式碼。
在我們所熟知的很多GUI工具包中,視窗小部件(widget)都有一個回撥函式用於響應它們能觸發的每個動作,這個回撥函式通常是一個指向某個函式的指標。但是,在QT中訊號和槽取代了這些凌亂的函式指標,使得我們編寫這些通訊程式更為簡潔明瞭。 訊號和槽能攜帶任意數量和任意型別的引數,他們是型別完全安全的,不會像回撥函式那樣產生core dumps。
所有從QObject或其子類(例如Qwidget)派生的類都能夠包含訊號和槽。當物件改變其狀態時,訊號就由該物件發射(emit)出去,這就是物件所要做的全部事情,它不知道另一端是誰在接收這個訊號。這就是真正的資訊封裝,它確保物件被當作一個真正的軟體元件來使用。槽用於接收訊號,但它們是普通的物件成員函式。一個槽並不知道是否有任何訊號與自己相連線。而且,物件並不瞭解具體的通訊機制。
你可以將很多訊號與單個的槽進行連線,也可以將單個的訊號與很多的槽進行連線,甚至於將一個訊號與另外一個訊號相連線也是可能的,這時無論第一個訊號什麼時候發射系統都將立刻發射第二個訊號。總之,訊號與槽構造了一個強大的部件程式設計機制。
二、訊號
當某個訊號對其客戶或所有者發生的內部狀態發生改變,訊號被一個物件發射。只有 定義過這個訊號的類及其派生類能夠發射這個訊號。當一個訊號被髮射時,與其相關聯的槽將被立刻執行,就象一個正常的函式呼叫一樣。訊號-槽機制完全獨立於任何GUI事件迴圈。只有當所有的槽返回以後發射函式(emit)才返回。 如果存在多個槽與某個訊號相關聯,那麼,當這個訊號被髮射時,這些槽將會一個接一個地 執行,但是它們執行的順序將會是隨機的、不確定的,我們不能人為地指定哪個先執行、哪 個後執行。
訊號的宣告是在標頭檔案中進行的,QT的signals關鍵字指出進入了訊號宣告區,隨後即可 宣告自己的訊號。例如,下面定義了三個訊號:
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);
在上面的定義中,signals是QT的關鍵字,而非C/C++的。接下來的一行void mySignal() 定義了訊號mySignal,這個訊號沒有攜帶引數;接下來的一行void mySignal(int x)定義 了重名訊號mySignal,但是它攜帶一個整形引數,這有點類似於C++中的虛擬函式。從形式上 講訊號的宣告與普通的C++函式是一樣的,但是訊號卻沒有函式體定義,另外,訊號的返回 型別都是void,不要指望能從訊號返回什麼有用資訊。
訊號由moc自動產生,它們不應該在.cpp檔案中實現。
三、槽
槽是普通的C++成員函式,可以被正常呼叫,它們唯一的特殊性就是很多訊號可以與其相關聯。當與其關聯的訊號被髮射時,這個槽就會被呼叫。槽可以有引數,但槽的引數不能有預設值。
既然槽是普通的成員函式,因此與其它的函式一樣,它們也有存取許可權。槽的存取許可權決定了誰能夠與其相關聯。同普通的C++成員函式一樣,槽函式也分為三種型別,即public slots、private slots和protected slots。
public slots:在這個區內宣告的槽意味著任何物件都可將訊號與之相連線。這對於元件程式設計非常有用,你可以建立彼此互不瞭解的物件,將它們的訊號與槽進行連線以便資訊能夠正確的傳遞。
protected slots:在這個區內宣告的槽意味著當前類及其子類可以將訊號與之相連線。這適用於那些槽,它們是類實現的一部分,但是其介面介面卻面向外部。
private slots:在這個區內宣告的槽意味著只有類自己可以將訊號與之相連線。這適用於聯絡非常緊密的類。
槽也能夠宣告為虛擬函式,這也是非常有用的。
槽的宣告也是在標頭檔案中進行的。例如,下面宣告瞭三個槽:
public slots:
void mySlot();
void mySlot(int x);
void mySignalParam(int x,int y);
四、訊號與槽的關聯
透過呼叫QObject物件的connect函式來將某個物件的訊號與另外一個物件的槽函式相關聯,這樣當發射者發射訊號時,接收者的槽函式將被呼叫。該函式的定義如下:
bool QObject::connect ( const QObject * sender, const char * signal,
const QObject * receiver, const char * member ) [static]
這個函式的作用就是將發射者sender物件中的訊號signal與接收者receiver中的member槽函式聯絡起來。當指定訊號signal時必須使用QT的宏SIGNAL(),當指定槽函式時必須使用宏SLOT()。如果發射者與接收者屬於同一個物件的話,那麼在connect呼叫中接收者引數可以省略。
例如,下面定義了兩個物件:標籤物件label和捲軸物件scroll,並將valueChanged()訊號與標籤物件的setNum()相關聯,另外訊號還攜帶了一個整形引數,這樣標籤總是顯示捲軸所處位置的值。
QLabel *label = new QLabel;
QScrollBar *scroll = new QScrollBar;
QObject::connect( scroll, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)) );
一個訊號甚至能夠與另一個訊號相關聯,看下面的例子:
class MyWidget : public QWidget
{
public:
MyWidget();
...
signals:
void aSignal();
...
private:
...
QPushButton *aButton;
};
MyWidget::MyWidget()
{
aButton = new QPushButton( this );
connect( aButton, SIGNAL(clicked()), SIGNAL(aSignal()) );
}
在上面的建構函式中,MyWidget建立了一個私有的按鈕aButton,按鈕的單擊事件產生的訊號clicked()與另外一個訊號aSignal()進行了關聯。這樣一來,當訊號clicked()被髮射時,訊號aSignal()也接著被髮射。當然,你也可以直接將單擊事件與某個私有的槽函式相關聯,然後在槽中發射aSignal()訊號,這樣的話似乎有點多餘。
當訊號與槽沒有必要繼續保持關聯時,我們可以使用disconnect函式來斷開連線。其定義如下:
bool QObject::disconnect ( const QObject * sender, const char * signal,
const Object * receiver, const char * member ) [static]
這個函式斷開發射者中的訊號與接收者中的槽函式之間的關聯。
有三種情況必須使用disconnect()函式:
斷開與某個物件相關聯的任何物件。這似乎有點不可理解,事實上,當我們在某個物件中定義了一個或者多個訊號,這些訊號與另外若干個物件中的槽相關聯,如果我們要切斷這些關聯的話,就可以利用這個方法,非常之簡潔。
disconnect( myObject, 0, 0, 0 )
或者
myObject->disconnect()
斷開與某個特定訊號的任何關聯。
disconnect( myObject, SIGNAL(mySignal()), 0, 0 )
或者
myObject->disconnect( SIGNAL(mySignal()) )
斷開兩個物件之間的關聯。
disconnect( myObject, 0, myReceiver, 0 )
或者
myObject->disconnect( myReceiver )
在disconnect函式中0可以用作一個萬用字元,分別表示任何訊號、任何接收物件、接收物件中的任何槽函式。但是發射者sender不能為0,其它三個引數的值可以等於0。
五、元物件工具
元物件編譯器moc(meta object compiler)對C++檔案中的類宣告進行分析併產生用於初始化元物件的C++程式碼,元物件包含全部訊號和槽的名字以及指向這些函式的指標。
moc讀C++原始檔,如果發現有Q_OBJECT宏宣告的類,它就會生成另外一個C++原始檔,這個新生成的檔案中包含有該類的元物件程式碼。例如,假設我們有一個標頭檔案mysignal.h,在這個檔案中包含有訊號或槽的宣告,那麼在編譯之前 moc 工具就會根據該檔案自動生成一個名為mysignal.moc.h的C++原始檔並將其提交給編譯器;類似地,對應於mysignal.cpp檔案moc工具將自動生成一個名為mysignal.moc.cpp檔案提交給編譯器。
元物件程式碼是signal/slot機制所必須的。用moc產生的C++原始檔必須與類實現一起進行編譯和連線,或者用#
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-949518/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Qt 自動連線機制訊號與槽QT
- C++ Qt開發:如何使用訊號與槽C++QT
- Qt之訊號與槽QT
- QT從入門到入土(三)——訊號和槽機制QT
- QT 控制檯訊號與槽簡例QT
- Qt - 訊號與槽的第五個引數QT
- linux 訊號機制Linux
- Qt 中多執行緒對應的訊號槽QT執行緒
- 02_QT訊號和槽QT
- Linux訊號(signal)機制Linux
- Qt訊號與槽使用方法最完整總結QT
- Qt 訊號槽傳遞指標QT指標
- Qt5的訊號和槽函式QT函式
- C++《QT之按鍵QPushButton設定訊號與槽》C++QT
- 《Qt5:訊號和槽使用示例》QT
- 如何在windows下發布QT應用程式(qt專案打包)WindowsQT
- QT學習筆記1(安裝、建立和訊號與槽)QT筆記
- Linux程式通訊機制Linux
- Qt自定義訊號槽的使用淺析+例項QT
- Android應用程式訊息處理機制Android
- QT槽函式獲取訊號傳送物件QT函式物件
- Sidecar 模式的機制與應用IDE模式
- Linux 下的程式間通訊:套接字和訊號Linux
- 訊號與槽N對N
- Linux 程式間通訊的六種機制Linux
- Qt學習第三篇(訊號槽函式的連線)QT函式
- 基於SkyEye執行Qt:著名應用程式開發框架QT框架
- PyQT5訊號與槽的連線QT
- iOS 訊息轉發機制Demo解析iOS
- Qt 5中使用lambda表示式連線訊號和槽QT
- 【Qt開發】更改應用程式圖示和工作列圖示QT
- pyqt5中訊號與槽的認識QT
- 冷門的 Java 應用程式安全沙箱機制瞭解一下Java
- PyQt4訊號與槽詳解QT
- 用linuxdeployqt吧Qt應用部署到LinuxLinuxQT
- Go通道機制與應用詳解Go
- iOS進階之訊息轉發機制iOS
- iOS應用轉讓到其他開發者賬號步驟iOS
- linux下qt用c++呼叫pythonLinuxQTC++Python