2.2 深入信号和槽(Signal and Slot in Depth)
www.diybl.com 时间 : 2008-07-09 作者:佚名 编辑:本站 点击: [ 评论 ]
2.2 深入信号和槽(Signal and Slot in Depth)
信号和槽机制是
Qt编程的基本。它使得程序员不需要知道对象相互关系就可以帮对象绑定在一起。我们已经实现过将一些信号和槽连接到一起,声明信号和槽,实现槽,以及发出的信号。下面我们花一些时间来深入研究下这个机制。
槽几乎和普通的
C++成员函数完全一样。它们都可以是虚函数(virtual);它们都可以被重载(overload);它们都可以是公共的(public),保护的(protected)或者私有的(private);它们都可以像其他C++成员函数一样被调用;他们的参数都可以是任何类型的。唯一的区别是,槽还可以被连接到信号,它将在每次信号发出后自动的被调用。
connect()语句是这样的:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
sender和
receiver是QObject的指针,signal和slot是不带参数的函数原型,SIGNAL()和SLOT()宏的作用是把它们的参数转换成了一个字符串。
在目前为止的例子中,我们总是把不同的信号连接到不同的槽。但是还有其它情况:
● 一个信号可以被连接到很多个槽:
connect(slider, SIGNAL(valueChange(int)),
spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChange(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会在一个对象被销毁时,自动移除它内部的所有连接。
为了成功地连接信号和槽(或另一个信号),它们必须有相同类型和顺序的参数:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(processReply(int, const QString &)));
值得注意的是,如果一个信号的参数有比要连接槽的多,则额外的参数将被忽略。
connect(ftp, SINGAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int)));
如果参数类型不同,或者信号或槽不存在,
Qt会在程序调试模式的运行时,发出一个警告。类似的,如果参数在信号或槽参数列表中已经存在,Qt也会发出一个警告。
目前为止,我们我们只是在控件中使用信号和槽。但是这种机制本身是在
QObject中实现的,而不限于GUI编程。这种机制可以在任何QObject的子类中使用:
class Employee : public QObject
{
QOBJECT
public:
Employee() { mySalary = 0; }
int salary() const { renturn mySalary; }
public slots:
void setSalary(int newSalary);
signals:
void salaryChanged(int newSalary);
private:
int mySalary;
};
Qt的Meta-Object系统
Qt的主要成就之一就是对
C++的扩展,这是一种用来把创建独立软件组件连接起来,而不需要知道它们相互间的任何细节。
这种结构被叫做
meta-object系统,它提供了两个关键服务:信号对槽和自省(introspection)。自省功能对于实现信号和槽是必须的,它允许程序员在程序运行时得到QObject子类的"meta-information",包括对象的信号和槽列表,以及类名。meta-object系统也支持属性(在Qt Designer中被广泛地使用)和文本转换(国际化支持),为QtScript模块奠定了基础。从Qt4.2开始,属性可以被动态地添加,关于此特性的介绍哦我们将在第19章和第22章看到。
标准
C++不提供对Qt的meta-object系统中,动态meta-information的支持。Qt是解决这个问题的方法是,提供一个单独的工具:moc,来解析Q_OBJECT类定义和用C++函数来获meta-information。由于moc是用纯C++来实现它所有功能的,因此Qt的meta-objedt系统可以在C++编译器下工作。
● Q_OBJECT宏声明了很多
QObject子类中中必须实现的自省函数:metaObject(),tr(),qt_metacall()等等。
● Qt的
moc工具为由Q_OBJECT声明的函数和所有信号产生代码。
●QObject成员函数,如
connect()和disconnect(),使用自省函数来工作。
所有这些都是由
qmake、moc和QObject来自动处理的,因此几乎不需要你考虑。但是,如果你很好奇,你可以阅读QMetaObject类的文档,然后看下moc自动产生的C++代码,来弄明白其中的原理。
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
注意
setSalary()槽是怎样实现的。只要newSalary != mySalary,我们发出salaryChanged()信号。这样避免了死循环的出现。