第二章 创建对话框(信号与槽进阶)

发布: 2008-05-29 22:17

信号与槽进阶


信号与槽的机制是 Qt 编程的基础。它使得应用程序程序员将对象与对象无隔阂的绑定在一起。我们已经将一些信号和槽连接在一起,声明了自己的信号和槽并实现了我们自己的槽,发出了自己信号。让我们花一些时间来仔细研究一下这一机制。


槽和普通的 C++ 成员函数几乎完全相同。它们可以使虚函数;可以被重载;可以是公开、保护或私有的,它们可以象其它 C++ 成员函数一样被直接调用;并且参数可以是任何数据类型。不同的是一个槽可以被连接到一个信号,在这种情况下当信号发出时它可以被自动调用。


connect() 语句看起来是这样的:


connect(sender, SIGNAL(signal), receiver, SLOT(slot));


 


sender receiver 是指向 QObjects 的指针,signal slot 是不带参数名的函数签名。SIGNAL() SLOT() 宏本质上将它们的参数转化成字符串。


在我们已经看到的例子中,我们总是连接不同的信号和不同的槽,其实,还有其它可能的选择。




  • 一个信号可以被连接到多个槽上:




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 会自动取消与对象相关的连接。


要成功连接一个信号到一个槽 (或到另一个信号)上,你必需拥相同的参数类型和顺序:


connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),


this, SLOT(processReply(int, const QString &)));


 


另外,如果一个信号比要连接槽拥有更多的参数,多余的参数会被简单的忽略掉:


connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),


this, SLOT(checkErrorCode(int)));


 


如果参数类型不兼容,又或者信号或槽不存在,如果应用程序在调试模式下编译Qt 会发出一个运行时警告。同样的,如果参数名被包含进信号或者槽的签名,Qt 会给出一个警告。


到目前为止,我们只用到了物件的信号与槽。但是信号与槽的机制本身是在 QObject 中实现的并且不仅仅用在 GUI 编程上。这个机制可以被 QObject 任何子类使用。:


class Employee : public QObject


{


Q_OBJECT


public:


Employee() { mySalary = 0; }


int salary() const { return mySalary; }


public slots:


void setSalary(int newSalary);


signals:


void salaryChanged(int newSalary);


private:


int mySalary;


};


void Employee::setSalary(int newSalary)


{


if (newSalary != mySalary) {


mySalary = newSalary;


emit salaryChanged(mySalary);


}


}


 


注意 setSalary () 是如何实现的。 我们仅当newSalary != mySalary成立的时候才发出salaryChanged()信号。这确保循环连接不会进入死循环。









Qt 的元对象系统


    Qt的一个主要特征是创建能绑定在一起但任意的组件都不需要知道它所连接的其他组件任何信息的独立软件组件的C++扩展机制。


    这个机制被称作元对象系统,它提供了两个关键服务:信号/槽和内省(introspection)。内省功能对实现信号和槽是必须的,它允许应用程序员在 运行期获得QObject子类的“元信息”,包括此对象支持的信号和槽的列表以及类名。此机制还支持属于(用于Qt 设计师)和文本翻译(用于国际化支持),它还是Qt 应用程序脚本(QSA)的基础。


   标准C++不提供Qt 元对象系统所需的动态元信息支持。Qt通过提供一个专用工具 于解析Q_OBJECT类定义和使得这些信息可在C++函数中可用的 moc 程序解决这个问题。由于moc使用纯C++实现所有的功能,Qt的元对象系统可工作在任何C++编译器上。


• Q_OBJECT宏定义了一些必须在所有QObject子类中实现的内省函数:metaObject(),TR(),qt_metacall()和其他一 些函数。

• Qt 的moc工具用于生成Q_OBJECT声明的函数和所有的信号的实现。

• QObject成员函数,如connect(),disconnect(),使用相关的内省函数实现它们的功能。


    所有这些事都由qmake,moc和QObject自动处理,因此你不需要老虎这些。但是如果你感兴趣,你可以找到QMetaObject类 文档看看,再看看由moc生成的C++源文件中如何实现这些功能的。



 



原文: http://qtchina.tk/?q=node/99

Powered by zexport