?? signalsandslots.html
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- /home/reggie/tmp/qt-3.0-reggie-5401/qt-win-commercial-3.0.5/doc/signalsandslots.doc:36 -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="Translator" content="Cavendish">
<meta name="Qt zh_CN Documents Website" content="http://www.qiliang.net/qt">
<title>信號和槽</title>
<style type="text/css"><!--
h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }
a:link { color: #004faf; text-decoration: none }
a:visited { color: #672967; text-decoration: none }
body { background: #ffffff; color: black; font-family: "Times New Roman" }
--></style>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr bgcolor="#E5E5E5">
<td valign=center>
<a href="index.html">
<font color="#004faf">主頁</font></a>
| <a href="classes.html">
<font color="#004faf">所有的類</font></a>
| <a href="mainclasses.html">
<font color="#004faf">主要的類</font></a>
| <a href="annotated.html">
<font color="#004faf">注釋的類</font></a>
| <a href="groups.html">
<font color="#004faf">分組的類</font></a>
| <a href="functions.html">
<font color="#004faf">函數</font></a>
</td>
<td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table>
<h1 align=center>信號和槽</h1>
<p> 信號和槽用于對象間的通訊。信號/槽機制是Qt的一個中心特征并且也許是Qt與
其它工具包的最不相同的部分。
<p> 在圖形用戶界面編程中,我們經常希望一個窗口部件的一個變化被通知給另一個
窗口部件。更一般地,我們希望任何一類的對象可以和其它對象進行通訊。例如,如
果我們正在解析一個XML文件,當我們遇到一個新的標簽時,我們也許希望通知列表
視圖我們正在用來表達XML文件的結構。
<p> 較老的工具包使用一種被稱作回調的通訊方式來實現同一目的。回調是指一個函
數的指針,所以如果你希望一個處理函數通知你一些事件,你可以把另一個函數(回
調)的指針傳遞給處理函數。處理函數在適當的時候調用回調。回調有兩個主要缺
點。首先他們不是類型安全的。我們從來都不能確定處理函數使用了正確的參數來調
用回調。其次回調和處理函數是非常強有力地聯系在一起的,因為處理函數必須知道
要調用哪個回調。
<p> <center><img src="abstract-connections.png"></center> <blockquote><p align="center"><em> 一個關于一些信號和槽連接的摘要圖
</em></p>
</blockquote><p> 在Qt中我們有一種可以替代回調的技術。我們使用信號和槽。當
一個特定事件發生的時候,一個信號被發射。Qt的窗口部件有很多預定義的信號,
但是我們總是可以通過繼承來加入我們自己的信號。槽就是一個可以被調用處理特定
信號的函數。Qt的窗口部件又很多預定義的槽,但是通常的習慣是你可以加入自己的
槽,這樣你就可以處理你所感興趣的信號。
<p> 信號和槽的機制是類型安全的:一個信號的簽名必須與它的接收槽的簽名相匹
配。(實際上一個槽的簽名可以比它接收的信號的簽名少,因為它可以忽略額外的
簽名。)因為簽名是一致的,編譯器就可以幫助我們檢測類型不匹配。信號和槽是
寬松地聯系在一起的:一個發射信號的類不用知道也不用注意哪個槽要接收這個信
號。Qt的信號和槽的機制可以保證如果你把一個信號和一個槽連接起來,槽會在正
確的時間使用信號的參數而被調用。信號和槽可以使用任何數量、任何類型的參
數。它們是完全類型安全的:不會再有回調核心轉儲(core dump)。
<p> 從<a href="qobject.html">QObject</a>類或者它的一個子類
(比如<a href="qwidget.html">QWidget</a>類)繼承的所有類可以包含信號和槽。
當對象改變它們的狀態的時候,信號被發送,從某種意義上講,它們也許對外面的
世界感興趣。這就是所有的對象通訊時所做的一切。它不知道也不注意無論有沒有
東西接收它所發射的信號。這就是真正的信息封裝,并且確保對象可以用作一個軟
件組件。
<p> <center><img src="concrete-connections.png"></center> <blockquote><p align="center"><em> 一個信號和槽連接的例子
</em></p>
</blockquote><p> 槽可以用來接收信號,但它們是正常的成員函數。一個槽不知道
它是否被任意信號連接。此外,對象不知道關于這種通訊機制和能夠被用作一個真正
的軟件組件。
<p> 你可以把許多信號和你所希望的單一槽相連,并且一個信號也可以和你所期望的
許多槽相連。把一個信號和另一個信號直接相連也是可以的。(這時,只要第一個信
號被發射時,第二個信號立刻就被發射。)
<p> 總體來看,信號和槽構成了一個強有力的組件編程機制。
<p> <h2> 一個小例子
</h2>
<a name="1"></a><p> 一個最小的C++類聲明如下:
<p> <pre>
class Foo
{
public:
Foo();
int value() const { return val; }
void setValue( int );
private:
int val;
};
</pre>
<p> 一個小的Qt類如下:
<p> <pre>
class Foo : public <a href="qobject.html">QObject</a>
{
<a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
public:
Foo();
int value() const { return val; }
public slots:
void setValue( int );
signals:
void valueChanged( int );
private:
int val;
};
</pre>
<p> 這個類有同樣的內部狀態,和公有方法來訪問狀態,但是另外它也支持使用信號
和槽的組件編程:這個類可以通過發射一個信號,<tt>valueChanged()</tt>,來告
訴外面的世界它的狀態發生了變化,并且它有一個槽,其它對象可以發送信號給這個
槽。
<p> 所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。
<p> 槽可以由應用程序的編寫者來實現。這里是Foo::setValue()的一個可能的實現:
<p> <pre>
void Foo::setValue( int v )
{
if ( v != val ) {
val = v;
emit valueChanged(v);
}
}
</pre>
<p> <tt>emit valueChanged(v)</tt>這一行從對象中發射<tt>valueChanged</tt>信
號。正如你所能看到的,你通過使用<tt>emit signal(arguments)</tt>來發射信號。
<p> 下面是把兩個對象連接在一起的一種方法:
<p> <pre>
Foo a, b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
b.setValue( 11 ); // a == undefined b == 11
a.setValue( 79 ); // a == 79 b == 79
b.value();
</pre>
<p> 調用<tt>a.setValue(79)</tt>會使<tt>a</tt>發射一個<tt>valueChanged()</tt>
信號,<tt>b</tt>將會在它的<tt>setValue()</tt>槽中接收這個信號,也就是<tt>b.setValue(79)</tt>
被調用。接下來<tt>b</tt>會發射同樣的<tt>valueChanged()</tt>信號,但是因為
沒有槽被連接到<tt>b</tt>的<tt>valueChanged()</tt>信號,所以沒有發生任何事
(信號消失了)。
<p> 注意只有當<tt>v != val</tt>的時候<tt>setValue()</tt>函數才會設置這個值
并且發射信號。這樣就避免了在循環連接的情況下(比如<tt>b.valueChanged()</tt>
和<tt>a.setValue()</tt>連接在一起)出現無休止的循環的情況。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -