用户名: 密   码:
   飞诺网 加入收藏
飞诺网 软件编程 C C++ Java VB Delphi Foxpro 汇编语言 游戏开发 移动开发 软件工程师 软工与管理 VC shell编程 C#
C++系列教程 C++实例 C++技术文档 C++/C语言函数 Mangos

您当前的位置:飞诺网 >> c/c++ >> C++实例

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));


 
senderreceiverQObject的指针,signalslot是不带参数的函数原型,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(),使用自省函数来工作。
 
所有这些都是由qmakemocQObject来自动处理的,因此几乎不需要你考虑。但是,如果你很好奇,你可以阅读QMetaObject类的文档,然后看下moc自动产生的C++代码,来弄明白其中的原理。
 
void Employee::setSalary(int newSalary)
{

    if (newSalary != mySalary) {

        mySalary = newSalary;

        emit salaryChanged(mySalary);


    }
}
 
注意setSalary()槽是怎样实现的。只要newSalary != mySalary,我们发出salaryChanged()信号。这样避免了死循环的出现。
 
 
 
如果图片或页面不能正常显示请点击这里
C++实例推荐文章

文章评论