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

KS05-04 信号-槽: disconnect的用途

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

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

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

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

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


引言
----------------------------------------------------------------
    前面几个章节中,我们为朋友们介绍了信号槽的绑定,其中包括使用自定义信号以及信号转发。这些内容都用到了connect,本节我们为朋友们讲一下disconnect,也就是解绑(断开连接),到底什么是解绑,为什么要解绑呢?本节为朋友们揭晓答案。

正文
----------------------------------------------------------------
    通过前面的课程,我们已经知道:将信号与槽绑定时需要调用connect()。而connect时需要提供发送者、接收者的地址。当发送者或者接收者已经不再活动时,我们可能也要将信号、槽解绑,以便将信号、槽绑定到新的活动对象。比如在一个多文档窗口程序中,当在某一个子窗口中选中文本时,我们将该文本内容显示在主窗口下方的状态栏中。这个功能我们可以使用信号槽绑定的方式实现。当我们点击选中子窗口A内的文本时,状态栏应显示A中被选中的文本,当点击选中子窗口B内的文本时,状态栏应显示B中被选中的文本。很明显,要实现该功能,我们就应该在子窗口的文本被选中时发出信号。当然,我们得先定义信号:
代码清单05-04-01
mdichild.h
  1. class MdiChild : public QTextEdit
  2. {
  3.     // ......
  4. Q_SIGNALS:
  5.         void textSelected(const QString&);
  6. };
复制代码
    然后在鼠标抬起时发出信号textSelected,见代码清单05-04-02第5行:
代码清单05-04-02

mdichild.cpp
  1. void MdiChild::mouseReleaseEvent(QMouseEvent *e) {

  2.         QTextCursor tc = textCursor();
  3.         QString strSelectedText = tc.selectedText().trimmed();
  4.         emit textSelected(strSelectedText);
  5.         
  6.         QTextEdit::mouseReleaseEvent(e);
  7. }
复制代码
最后,当子窗口被激活时,将被激活的子窗口发出的信号textSelected与主窗口的槽函数进行绑定。
    在此之前,我们先要将子窗口激活信号QMdiArea::subWindowActivated绑定到主窗口的槽函数,见代码清单05-04-03第7行:
代码清单05-04-03

mainwindow.cpp
  1. MainWindow::MainWindow()
  2.     : mdiArea(new QMdiArea), m_pLastChild(NULL)
  3. {
  4.     mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  5.     mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  6.     setCentralWidget(mdiArea);
  7.     connect(mdiArea, &QMdiArea::subWindowActivated,
  8.         this, &MainWindow::slot_SubWindowActivated);
  9. }
复制代码
然后,在该槽函数中将子窗口的信号textSelected与主窗口的槽函数执行绑定操作,见代码清单05-04-04中第3~4行:
代码清单05-04-04

mainwindow.cpp
  1. void MainWindow::slot_SubWindowActivated()
  2. {
  3. connect(activeMdiChild(), &MdiChild::textSelected, this,         
  4.         &MainWindow::slot_TextSelected);
  5. }
复制代码
在MainWindow的槽函数slot_TextSelected()中:
  1. void MainWindow:: slot_TextSelected(const QString& strTextSelected) {
  2.         statusBar()->showMessage(strTextSelected);
  3. }
复制代码
这样,当子窗口切换后,当选中子窗口中的文本时,主窗口的状态栏就可以显示当前活动子窗口中刚刚被选中的文本。
整个功能似乎开发完毕。当我们切换子窗口时,将新激活的子窗口发出的消息与主窗体的槽函数进行绑定。但是请不要忘记,失去焦点的旧的子窗口之前曾经参与过绑定。如果每次被激活都重新绑定,那么将导致内存泄漏;而且因为多次绑定会导致触发多次槽函数的重复调用,这也是不正确的。正确的做法是每次激活新的子窗口时,应当先把失去焦点的子窗口的信号解绑。为此,我们为主窗口定义一个成员变量m_pLastChild用来保存上次的活动子窗口。因此代码清单05-04-04变成这样:
代码清单05-04-05

mainwindow.cpp
  1. void MainWindow::onSubWindowActivated()
  2. {
  3.         if (NULL != m_pLastChild) {
  4.                 if (activeMdiChild() != m_pLastChild) {
  5. // 过滤掉最小化后的还原事项或者其他类似事项
  6.                         disconnect(m_pLastChild, &MdiChild::textSelected,
  7.                          this, &MainWindow::slot_TextSelected);
  8.                         connect(activeMdiChild(), &MdiChild::textSelected,
  9.                    this, &MainWindow::slot_TextSelected);
  10.                 }
  11.         }        
  12.         m_pLastChild = activeMdiChild();
  13.    // ……
  14. }
复制代码
在代码清单05-04-05中,我们先用disconnect()解除旧的信号槽绑定,然后用connect()建立新的绑定关系。请注意,disconnect()的语法跟connect一致。

结语
----------------------------------------------------------------
   本节中,我们给出了需要调用disconnect解除信号槽绑定的一种示例。读者可以根据自己平时工作、学习中的各种业务场景进行灵活处理,在合适的地方执行绑定或解绑操作。


----------------------------------------------------------------

回复

使用道具 举报

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

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