Qt入门(3)——信号和槽
生活随笔
收集整理的這篇文章主要介紹了
Qt入门(3)——信号和槽
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
信號和槽用于對象間的通訊。信號/槽機制是Qt的一個中心特征并且也許是Qt與其它工具包的最不相同的部分。
在圖形用戶界面編程中,我們經常希望一個窗口部件的一個變化被通知給另一個窗口部件。更一般地,我們希望任何一類的對象可以和其它對象進行通訊。例如,如果我們正在解析一個XML文件,當我們遇到一個新的標簽時,我們也許希望通知列表視圖我們正在用來表達XML文件的結構。
較老的工具包使用一種被稱作回調的通訊方式來實現同一目的。回調是指一個函數的指針,所以如果你希望一個處理函數通知你一些事件,你可以把另一個函數(回調)的指針傳遞給處理函數。處理函數在適當的時候調用回調。回調有兩個主要缺點。首先他們不是類型安全的。我們從來都不能確定處理函數使用了正確的參數來調用回調。其次回調和處理函數是非常強有力地聯系在一起的,因為處理函數必須知道要調用哪個回調。
在Qt中我們有一種可以替代回調的技術。我們使用信號和槽。當一個特定事件發生的時候,一個信號被發射。Qt的窗口部件有很多預定義的信號,但是我們總是可以通過繼承來加入我們自己的信號。槽就是一個可以被調用處理特定信號的函數。Qt的窗口部件又很多預定義的槽,但是通常的習慣是你可以加入自己的槽,這樣你就可以處理你所感興趣的信號。
信號和槽的機制是類型安全的:一個信號的簽名必須與它的接收槽的簽名相匹配。(實際上一個槽的簽名可以比它接收的信號的簽名少,因為它可以忽略額外的簽名。)因為簽名是一致的,編譯器就可以幫助我們檢測類型不匹配。信號和槽是寬松地聯系在一起的:一個發射信號的類不用知道也不用注意哪個槽要接收這個信號。Qt的信號和槽的機制可以保證如果你把一個信號和一個槽連接起來,槽會在正確的時間使用信號的參數而被調用。信號和槽可以使用任何數量、任何類型的參數。它們是完全類型安全的:不會再有回調核心轉儲(core dump)。
從QObject類或者它的一個子類(比如QWidget類)繼承的所有類可以包含信號和槽。當對象改變它們的狀態的時候,信號被發送,從某種意義上講,它們也許對外面的世界感興趣。這就是所有的對象通訊時所做的一切。它不知道也不注意無論有沒有東西接收它所發射的信號。這就是真正的信息封裝,并且確保對象可以用作一個軟件組件。
槽可以用來接收信號,但它們是正常的成員函數。一個槽不知道它是否被任意信號連接。此外,對象不知道關于這種通訊機制和能夠被用作一個真正的軟件組件。
你可以把許多信號和你所希望的單一槽相連,并且一個信號也可以和你所期望的許多槽相連。把一個信號和另一個信號直接相連也是可以的。(這時,只要第一個信號被發射時,第二個信號立刻就被發射。)
總體來看,信號和槽構成了一個強有力的組件編程機制。?
一個最小的C++類聲明:
class Foo{public:Foo();int value() const { return val; }void setValue( int );private:int val;};
一個小的Qt類如下:
class Foo : public QObject{Q_OBJECTpublic:Foo();int value() const { return val; }public slots:void setValue( int );signals:void valueChanged( int );private:int val;};
這個類有同樣的內部狀態,和公有方法來訪問狀態,但是另外它也支持使用信號和槽的組件編程:這個類可以通過發射一個信號,valueChanged(),來告訴外面的世界它的狀態發生了變化,并且它有一個槽,其它對象可以發送信號給這個槽。
所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。
槽可以由應用程序的編寫者來實現。這里是Foo::setValue()的一個可能的實現:
void Foo::setValue( int v ){if ( v != val ) {val = v;emit valueChanged(v);}}
這個類有同樣的內部狀態,和公有方法來訪問狀態,但是另外它也支持使用信號和槽的組件編程:這個類可以通過發射一個信號,valueChanged(),來告訴外面的世界它的狀態發生了變化,并且它有一個槽,其它對象可以發送信號給這個槽。
? ? 所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。
槽可以由應用程序的編寫者來實現。這里是Foo::setValue()的一個可能的實現:
void Foo::setValue( int v ){if ( v != val ) {val = v;emit valueChanged(v);}}
emit valueChanged(v)這一行從對象中發射valueChanged信號。正如你所能看到的,你通過使用emit signal(arguments)來發射信號。
下面是把兩個對象連接在一起的一種方法:
Foo a, b;connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));b.setValue( 11 ); // a == undefined b == 11a.setValue( 79 ); // a == 79 b == 79b.value();
調用a.setValue(79)會使a發射一個valueChanged() 信號,b將會在它的setValue()槽中接收這個信號,也就是b.setValue(79) 被調用。接下來b會發射同樣的valueChanged()信號,但是因為沒有槽被連接到b的valueChanged()信號,所以沒有發生任何事(信號消失了)。
注意只有當v != val的時候setValue()函數才會設置這個值并且發射信號。這樣就避免了在循環連接的情況下(比如b.valueChanged() 和a.setValue()連接在一起)出現無休止的循環的情況。
這個例子說明了對象之間可以在互相不知道的情況下一起工作,只要在最初的時在它們中間建立連接。
預處理程序改變或者移除了signals、slots和emit 這些關鍵字,這樣就可以使用標準的C++編譯器。
在一個定義有信號和槽的類上運行moc。這樣就會生成一個可以和其它對象文件編譯和連接成引用程序的C++源文件。
在圖形用戶界面編程中,我們經常希望一個窗口部件的一個變化被通知給另一個窗口部件。更一般地,我們希望任何一類的對象可以和其它對象進行通訊。例如,如果我們正在解析一個XML文件,當我們遇到一個新的標簽時,我們也許希望通知列表視圖我們正在用來表達XML文件的結構。
較老的工具包使用一種被稱作回調的通訊方式來實現同一目的。回調是指一個函數的指針,所以如果你希望一個處理函數通知你一些事件,你可以把另一個函數(回調)的指針傳遞給處理函數。處理函數在適當的時候調用回調。回調有兩個主要缺點。首先他們不是類型安全的。我們從來都不能確定處理函數使用了正確的參數來調用回調。其次回調和處理函數是非常強有力地聯系在一起的,因為處理函數必須知道要調用哪個回調。
在Qt中我們有一種可以替代回調的技術。我們使用信號和槽。當一個特定事件發生的時候,一個信號被發射。Qt的窗口部件有很多預定義的信號,但是我們總是可以通過繼承來加入我們自己的信號。槽就是一個可以被調用處理特定信號的函數。Qt的窗口部件又很多預定義的槽,但是通常的習慣是你可以加入自己的槽,這樣你就可以處理你所感興趣的信號。
信號和槽的機制是類型安全的:一個信號的簽名必須與它的接收槽的簽名相匹配。(實際上一個槽的簽名可以比它接收的信號的簽名少,因為它可以忽略額外的簽名。)因為簽名是一致的,編譯器就可以幫助我們檢測類型不匹配。信號和槽是寬松地聯系在一起的:一個發射信號的類不用知道也不用注意哪個槽要接收這個信號。Qt的信號和槽的機制可以保證如果你把一個信號和一個槽連接起來,槽會在正確的時間使用信號的參數而被調用。信號和槽可以使用任何數量、任何類型的參數。它們是完全類型安全的:不會再有回調核心轉儲(core dump)。
從QObject類或者它的一個子類(比如QWidget類)繼承的所有類可以包含信號和槽。當對象改變它們的狀態的時候,信號被發送,從某種意義上講,它們也許對外面的世界感興趣。這就是所有的對象通訊時所做的一切。它不知道也不注意無論有沒有東西接收它所發射的信號。這就是真正的信息封裝,并且確保對象可以用作一個軟件組件。
槽可以用來接收信號,但它們是正常的成員函數。一個槽不知道它是否被任意信號連接。此外,對象不知道關于這種通訊機制和能夠被用作一個真正的軟件組件。
你可以把許多信號和你所希望的單一槽相連,并且一個信號也可以和你所期望的許多槽相連。把一個信號和另一個信號直接相連也是可以的。(這時,只要第一個信號被發射時,第二個信號立刻就被發射。)
總體來看,信號和槽構成了一個強有力的組件編程機制。?
一個最小的C++類聲明:
class Foo{public:Foo();int value() const { return val; }void setValue( int );private:int val;};
一個小的Qt類如下:
class Foo : public QObject{Q_OBJECTpublic:Foo();int value() const { return val; }public slots:void setValue( int );signals:void valueChanged( int );private:int val;};
這個類有同樣的內部狀態,和公有方法來訪問狀態,但是另外它也支持使用信號和槽的組件編程:這個類可以通過發射一個信號,valueChanged(),來告訴外面的世界它的狀態發生了變化,并且它有一個槽,其它對象可以發送信號給這個槽。
所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。
槽可以由應用程序的編寫者來實現。這里是Foo::setValue()的一個可能的實現:
void Foo::setValue( int v ){if ( v != val ) {val = v;emit valueChanged(v);}}
這個類有同樣的內部狀態,和公有方法來訪問狀態,但是另外它也支持使用信號和槽的組件編程:這個類可以通過發射一個信號,valueChanged(),來告訴外面的世界它的狀態發生了變化,并且它有一個槽,其它對象可以發送信號給這個槽。
? ? 所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。
槽可以由應用程序的編寫者來實現。這里是Foo::setValue()的一個可能的實現:
void Foo::setValue( int v ){if ( v != val ) {val = v;emit valueChanged(v);}}
emit valueChanged(v)這一行從對象中發射valueChanged信號。正如你所能看到的,你通過使用emit signal(arguments)來發射信號。
下面是把兩個對象連接在一起的一種方法:
Foo a, b;connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));b.setValue( 11 ); // a == undefined b == 11a.setValue( 79 ); // a == 79 b == 79b.value();
調用a.setValue(79)會使a發射一個valueChanged() 信號,b將會在它的setValue()槽中接收這個信號,也就是b.setValue(79) 被調用。接下來b會發射同樣的valueChanged()信號,但是因為沒有槽被連接到b的valueChanged()信號,所以沒有發生任何事(信號消失了)。
注意只有當v != val的時候setValue()函數才會設置這個值并且發射信號。這樣就避免了在循環連接的情況下(比如b.valueChanged() 和a.setValue()連接在一起)出現無休止的循環的情況。
這個例子說明了對象之間可以在互相不知道的情況下一起工作,只要在最初的時在它們中間建立連接。
預處理程序改變或者移除了signals、slots和emit 這些關鍵字,這樣就可以使用標準的C++編譯器。
在一個定義有信號和槽的類上運行moc。這樣就會生成一個可以和其它對象文件編譯和連接成引用程序的C++源文件。
轉載于:https://www.cnblogs.com/new0801/p/6176961.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Qt入门(3)——信号和槽的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UITableView的UITableV
- 下一篇: 20140904 atoi字符串转化为整