来源http://blog.csdn.net/lazydreamhunter/article/details/8539898
最近在使用QTabWidget控件的时候发现,QTabWidget控件的addTab(pWidget, "myTab")方法会改变pWidget控件原有父子关系,因为这个问题,害我找了半天,我本意是想通过pWidget->parent()获取pWidget的父指针,但是由于addTab会改变pWidget的原来的父子关系,导致找不到原来的父指针,下面我们来看看addTab是怎么来改变这个父指针的:
首先看一段简单的应用代码:
#ifndef _INFO_H
#define _INFO_H
#include <QtGui>
class CInfo1 : public QWidget {
public:
CInfo1(QWidget *parent) : QWidget(parent)
{
}
void getResult();
};
class CInfo2 : public QWidget {
public:
CInfo2(QWidget *parent) : QWidget(parent)
{
}
void getResult();
};
class CInfo : public QTabWidget {
public:
CInfo(QWidget *parent = NULL) : QTabWidget(parent)
{
pInfo1 = new CInfo1(this);
pInfo2 = new CInfo2(this);
addTab(pInfo1, "info1");
addTab(pInfo2, "info2");
a = 1;
b = 2;
qDebug() << a << b;
}
CInfo1 *pInfo1;
CInfo2 *pInfo2;
int a;
int b;
};
#endif
#include "info.h"void CInfo1::getResult(){CInfo *pInfo = (CInfo *)parent();qDebug() << pInfo->a << pInfo->b;}void CInfo2::getResult(){CInfo *pInfo = (CInfo *)parent();qDebug() << pInfo->a << pInfo->b;}
int main(int argc, char *argv[]){QApplication a(argc, argv);CInfo info;info.pInfo1->getResult();
info.pInfo2->getResult();
info.show();
return a.exec();}从上面的代码若父指针没有更改,则会打印出三行:
1 2
1 2
1 2
而事实的打印却是:
1 2
X X
X X
X是一个随机数,从而我们不难发现,getResult()函数里的parent()已不是指向info对象了,接下来我们看看到底addTab是怎么改变父指针的,看一下调用关系:
addTab(pInfo1, "info1");int QTabWidget::addTab(QWidget *child, const QString &label){return insertTab(-1, child, label);}int QTabWidget::insertTab(int index, QWidget *w, const QIcon& icon, const QString &label){Q_D(QTabWidget);if(!w)return -1;index = d->stack->insertWidget(index, w);d->tabs->insertTab(index, icon, label);setUpLayout();
tabInserted(index);
return index;}int QStackedWidget::insertWidget(int index, QWidget *widget){return d_func()->layout->insertWidget(index, widget);}int QStackedLayout::insertWidget(int index, QWidget *widget){Q_D(QStackedLayout);addChildWidget(widget);index = qMin(index, d->list.count());if (index < 0)index = d->list.count();QWidgetItem *wi = QLayoutPrivate::createWidgetItem(this, widget);d->list.insert(index, wi);invalidate();
if (d->index < 0) {setCurrentIndex(index);
} else {if (index <= d->index)++d->index;
if (d->stackingMode == StackOne)widget->hide();
widget->lower();
}
return index;}void QLayout::addChildWidget(QWidget *w){QWidget *mw = parentWidget();QWidget *pw = w->parentWidget();
//Qt::WA_LaidOut is never reset. It only means that the widget at some point has//been in a layout.if (pw && w->testAttribute(Qt::WA_LaidOut)) {QLayout *l = pw->layout();if (l && removeWidgetRecursively(l, w)) {#ifdef QT_DEBUGif (layoutDebug())qWarning("QLayout::addChildWidget: %s \"%s\" is already in a layout; moved to new layout",w->metaObject()->className(), w->objectName().toLocal8Bit().data());#endif
}
}
if (pw && mw && pw != mw) {#ifdef QT_DEBUGif (layoutDebug())qWarning("QLayout::addChildWidget: %s \"%s\" in wrong parent; moved to correct parent",w->metaObject()->className(), w->objectName().toLocal8Bit().data());#endif
pw = 0;}
bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));if (!pw && mw)w->setParent(mw);
w->setAttribute(Qt::WA_LaidOut);if (needShow)QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later}从调用栈(注意红色代码)发现,最终addTab会调用addChildWidget,在w->setParent会将pWidget的父指针更改,哈哈,终于水落石出了。