信号与槽会失联,一般是因为其中一个对象被delete了,再就是人为地调用了disconnect()函数.
回到正题,在使用Qt的MDI框架时,我用类A和类B分别继承了QMdiArea和QMdiSubWindow,再分别实例化出A_obj,B_obj,把B_obj
放到A_obj中,后面因为功能需要,我通过setParent的方式将B_obj从A_obj中独立出来,这会,先前A_obj与B_obj建立好的信号-槽就失效了.
查看了源码才知道原因:
源码片段1:
bool QMdiArea::viewportEvent(QEvent *event)
{
Q_D(QMdiArea);
switch (event->type()) {
case QEvent::ChildRemoved: {
d->isSubWindowsTiled = false;
QObject *removedChild = static_cast<QChildEvent *>(event)->child();
for (int i = 0; i < d->childWindows.size(); ++i) {
QObject *child = d->childWindows.at(i);
if (!child || child == removedChild || !child->parent()
|| child->parent() != viewport()) {
if (!testOption(DontMaximizeSubWindowOnActivation)) {
// In this case we can only rely on the child being a QObject
// (or 0), but let's try and see if we can get more information.
QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
if (mdiChild && mdiChild->isMaximized())
d->showActiveWindowMaximized = true;
}
d->disconnectSubWindow(child);
const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
d->childWindows.removeAt(i);
d->indicesToActivatedChildren.removeAll(i);
d->updateActiveWindow(i, activeRemoved);
d->arrangeMinimizedSubWindows();
break;
}
}
d->updateScrollBars();
break;
}
case QEvent::Destroy:
d->isSubWindowsTiled = false;
d->resetActiveWindow();
d->childWindows.clear();
qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");
break;
default:
break;
}
return QAbstractScrollArea::viewportEvent(event);
}
从源码片段1中,我们可以知道,当使用setParent后,B_obj独立出来,那么A_obj的孩子就少了一个,于是会触发viewportEvent(QEvent *event)事件,继而会调用d->disconnectSubWindow(child);那么这个disconnectSubWindow函数又做了些什么呢?
void QMdiAreaPrivate::disconnectSubWindow(QObject *subWindow)
{
if (!subWindow)
return;
Q_Q(QMdiArea);
QObject::disconnect(subWindow, 0, q, 0);
subWindow->removeEventFilter(q);
}
看到倒数第二句便知,此时切断了与孩子的所有信号与槽的联系.