在Qt中,有一种用于对象之间的通信:信号-槽机制,这种机制是Qt的核心机制,也是它区别于其他GUI工具的最主要的特征。信号-槽机制可以携带任意类型、任意数量的参数,而且完全是安全的,不会引起系统的崩溃。用户可以按照需要将许多信号与一个单独的槽函数相联系,一个信号也可以按需要被联系到很多不同的槽函数。甚至还可以将一个信号直接与另一个信号相联系,这样当第一个信号被发出时立刻发出第二个信号。
当某个信号所对应的客户或其所有者的内部状态发生改变时,信号被一个对象发射。只有定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的
槽将被立刻执行,就象调用一个正常的函数一样。信号-槽机制完全独立于任何GUI事件循环。只有当所有的槽返回以后发射函数(emit)才返回。如果存在多个槽与某个信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪个后执行。例如,一个列表框可以发出highlighted()和activated()的信号,大多数对象也许只对activated()的信号感兴趣,但也许
有些对象需要知道该列表框中的哪一项被选中了。如果有两个不同的对象对一个信号感兴趣,只要将该信号连接到这两个对象的槽上就可以了。
Signal和Slot的声明
在Qt程序设计中,凡是包含signal和slot的类中都要加上Q_OBJECT的定义,下面的例子给出了如何在一个类中定义signal和slot:
class Student : public QObject
{
Q_OBJECT
public:
Student() { myMark = 0; }
int mark() const { return myMark; }
public slots:
void setMark(int newMark);
signals:
void markChanged(int newMark);
private:
int myMark;
};
signal和slot在类体内通常声明为void型成员函数,允许带参数signal 不需要实体,slot必须要有实体,否则错误就同声明一个函数却没有实体一样,会发生链接错误
signal的发出一般在事件的处理函数中,利用emit发出signal,在下面的例子中在在事件处理结束后发出signal
void Student::setMark(int newMark)
{
if (newMark!= myMark) {
myMark = newMark;
emit markChanged(myMark);
}
}
Signal和Slot的连接
在signal和slot声明以后,需要使用connect()函数将它们连接起来。connect()函数属于QObject类的成员函数,它能够连接signal和slot,也可以用来连接signal和signal函数原形如下:
bool connect ( const QObject * sender, const char * signal,const char * member ) const
其中第一个和第三个参数分别指出signal和slot是属于那个对象或组件
在使用connect()函数进行来接的时候,还需要用到SIGNAL()和SLOT()这两个宏,使用方法如下:
QLabel *label = new QLabel;
QScrollBar *scroll = new QScrollBar;
QObject::connect( scroll,SIGNAL(valueChanged(int)),label, SLOT(setNum(int)) );
同一个信号连接多个插槽
connect(slider, SIGNAL(valueChanged(int)),spinBox,SLOT(setValue(int)));
connect(slider,SIGNAL(valueChanged(int)),this,SLOT(updateStatusBarIndicator(int)));
多个信号连接到同一个插槽
connect(lcd, SIGNAL(overflow()),this,SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),this,SLOT(handleMathError()));
一个信号连接到另一个信号
connect(lineEdit, SIGNAL(textChanged(const QString&)),this, SIGNAL(updateRecord(const QString&)));
取消一个连接
disconnect(lcd,SIGNAL(overflow()),this,SLOT(handleMathError()));
取消一个连接不是很常用,因为Qt会在一个对象被删除后自动取消这个对象所包含的所有的连接