找回密码
 立即注册
收起左侧

KS05-03 信号-槽:自定义signal与信号转发

0
回复
4426
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2019-9-2 16:46:35 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2019-9-2 16:51 编辑

该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白
转载请注明出处!
----------------------------------------------------------------


引言
----------------------------------------------------------------
    利用Qt提供的信号槽机制可以将一个信号与槽函数关联起来,方法是将信号和槽进行connect。上一节讲了利用Qt类自带的信号进行绑定,本节讲一下如何使用自定义信号。另外,上一节讲的是直接将信号绑定到槽函数,本节讲一下把信号继续转发。

正文
----------------------------------------------------------------
    上一节讲到,信号、槽跟普通的函数类似,只是需要把信号写到"Q_SIGNALS:"的后面,把槽函数写到"slots:"后面。槽函数有public、protected、private之分,而信号则没有。
    有时候Qt提供的信号并不能满足我们的需求。比如,当结束编辑的时候,我们需要将编辑后的文本发给接收者以便接收者进行展示或进行其他处理,这时候就需要我们定义自己的信号。实现自定义信号的方法是在发出信号的类中对信号进行定义:
代码清单05-03-01
address.h
  1. class CWidgetAddress : public QWidget
  2. {
  3. // ……
  4. Q_SIGNALS:
  5.          void sit_addressSaved(const QString& strAddress);
  6. };
复制代码
    信号可以带参数,也可以不带参数。槽函数的参数列表要保证跟信号的参数列表完全一致,否则将导致信号槽绑定失败。如果带参数,请给出有意义的参数对象的名称。但在执行connect时请不要写参数对象的变量名称。
    有了信号,那么就可以在适当的时机将信号发出去。语法是:
  1. emit  信号(参数对象列表)
复制代码
    在本节的示例中,我们在按下按钮的时候将上面的信号发出:
代码清单05-03-02

address.cpp
  1. void CWidgetAddress:: slot_btnSaveClicked(){
  2.         emit sig_addressSaved(ui.m_lineEdit->text());
  3. }
复制代码
在emit信号时,需要将信号的参数实例化,也就是在信号中的参数填写具体的内容。比如代码清单05-03-02中第2行,我们用ui.m_lineEdit->text()返回的对象作为信号的参数执行emit。
为了业务方便,我们可以为同一个类添加多个不同的信号。

下面讨论本节的第二个内容:将信号转发出去。
有时候,我们收到某个信号后需要转手继续发给别人。原因可能是信号的真正接收者根本无法访问信号发送者对象地址,也就无法使用connect()将信号发送者与槽函数拥有者直接建立关联。这就需要有个中间转发过程。
本节的示例中,CDialog对象在收到pWidgetAddress的sig_addressSaved信号后,需要把它继续转发。既然要转发信号,那么就要为CDialog定义这个信号,总不能转发别人名下的信号吧(Qt的信号槽机制仅支持使用某个类自身的信号或者其父类中存在的信号,不能使用其他类的信号)。这里,为了区别于子控件pWidgetAddress的信号,我们把CDialog的信号取名sig_addressUpdated(其实,如果跟子控件信号名称一致也可以)。
代码清单05-03-03

dialog.h
  1. class CDialog : public QDialog
  2. {
  3. // ……
  4. Q_SIGNALS:
  5.         void sig_addressUpdated(const QString& strAddress);
  6. };
复制代码
转发的语法很简单,也是用connect,只是将最后的SLOT()改为SIGNAL()。比如:
代码清单05-03-04

dialog.cpp
  1. connect(pWidgetAddress, SIGNAL(addressSaved(const QString &)),
  2. this, SIGNAL(sig_addressUpdated (const QString &)));
复制代码
当然,也可以用函数地址的写法:
代码清单05-03-05

dialog.cpp
  1. connect(pWidgetAddress, &CWidgetAddress::addressSaved,
  2.         this, &CDialog::sig_addressUpdated);
复制代码
在代码清单05-03-05中,将pWidgetAddress发出的信号addressSaved(const QString &)继续通过this(CDialog类对象)进行转发,转发出的信号为sig_addressUpdated(const QString &)。
    然后,在能够同时访问信号发送者与接收者的地方将CDialog转发的这个信号与接收者的槽函数进行绑定:
代码清单05-03-06

main.cpp
  1. QObject::connect(&dlg, &CDialog::sig_addressUpdated,
  2.                  pSimpleDialog, &CSimpleDialog::slot_updateAddress);
复制代码
    请注意,在代码清单05-03-06中,并没有直接调用connect,而是调用QObject::connect()。这是因为执行这行代码的位置是main()函数而非某个QObject派生的类,所以我们借用了QObject提供的static函数connect()来完成信号槽的绑定。


结语
----------------------------------------------------------------
   本节介绍了自定义信号的方法以及将信号转发的方法,总结如下:
    1. 可以在类中添加自定义信号,方法是加到"Q_SIGNALS:"后面。
    2. 信号可以带参数,也可以不带。参数最好具有名字。
    3. 使用emit发出信号。
    4. 转发时需要为转发者定义自己的信号,信号名称可以与原始信号不同(也可以相同),但是参数列表必须完全一致。转发信号时使用SIGNAL()而非SLOT()。当然,如果不想使用connect()宏,也可以使用函数地址的语法进行转发。
    5. 在能够同时访问信号发送者(转发者)与信号接收者的代码处将转发信号跟槽函数进行绑定。

    6. 如果类并非派生自QObject,则可以使用QObject::connect()完成信号槽的绑定。

----------------------------------------------------------------
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了