本文記錄QChildEvent事件相關代碼分析。
注1:限于筆者研究水平,難免有表述不當,歡迎批評指正。
注2:博文會不定期更新,敬請關注。
一、QChildEvent的發送
分析QObject::setParent代碼,當修改父對象時,便會舊parent發送QEvent::ChildRemoved事件;向新parent發送QEvent::ChildAdded事件。
/*!Makes the object a child of \a parent.\sa parent(), children()
*/
void QObject::setParent(QObject *parent)
{Q_D(QObject);Q_ASSERT(!d->isWidget);d->setParent_helper(parent);
}
void QObjectPrivate::setParent_helper(QObject *o)
{Q_Q(QObject);Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
#ifdef QT_DEBUGconst auto checkForParentChildLoops = qScopeGuard([&](){int depth = 0;auto p = parent;while (p) {if (++depth == CheckForParentChildLoopsWarnDepth) {qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; ""this is undefined behavior",q, q->metaObject()->className(), qPrintable(q->objectName()));}p = p->parent();}});
#endifif (o == parent)return;if (parent) {QObjectPrivate *parentD = parent->d_func();if (parentD->isDeletingChildren && wasDeleted&& parentD->currentChildBeingDeleted == q) {// don't do anything since QObjectPrivate::deleteChildren() already// cleared our entry in parentD->children.} else {const int index = parentD->children.indexOf(q);if (parentD->isDeletingChildren) {parentD->children[index] = 0;} else {parentD->children.removeAt(index);if (sendChildEvents && parentD->receiveChildEvents) {QChildEvent e(QEvent::ChildRemoved, q);QCoreApplication::sendEvent(parent, &e);}}}}parent = o;if (parent) {// object hierarchies are constrained to a single threadif (threadData != parent->d_func()->threadData) {qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");parent = 0;return;}parent->d_func()->children.append(q);if(sendChildEvents && parent->d_func()->receiveChildEvents) {if (!isWidget) {QChildEvent e(QEvent::ChildAdded, q);QCoreApplication::sendEvent(parent, &e);}}}if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
}
因為QObject構造函數可以設置parent,此時發送QChildEvent事件,但對象并不一定創建完畢。
Refs. from QObject::childEvent(QChildEvent *)
QEvent::ChildAdded?and?QEvent::ChildRemoved?events are sent to objects when children are added or removed. In both cases you can only rely on the child being a?QObject, or if?isWidgetType() returns?
true
, a?QWidget. (This is because, in the?ChildAdded?case, the child is not yet fully constructed, and in the?ChildRemoved?case it might have been destructed already).
二、應用案例
在SALOME中,SUIT_Desktop通過響應QChildEvent消息來講SUIT_ViewWindow添加到SUIT_Desktop中。
class SUIT_Desktop::ReparentEvent : public QEvent
{
public:ReparentEvent( Type t, QObject* obj ) : QEvent( t ), myObj( obj ) {};QObject* object() const { return myObj; }private:QPointer<QObject> myObj;
};
/*!Child event.
*/
void SUIT_Desktop::childEvent( QChildEvent* e )
{if ( e->type() == QEvent::ChildAdded && e->child()->isWidgetType() ) {// The following line is a workaround to avoid showing view window as a top-level window// before re-parenting it to workstack (issue #23467).// See SUIT_ViewWindow::setVisible() and SUIT_Desktop::customEvent().e->child()->setProperty("blockShow", true );QApplication::postEvent( this, new ReparentEvent( QEvent::Type( Reparent ), e->child() ) );}else {QtxMainWindow::childEvent( e );}
}void SUIT_Desktop::customEvent( QEvent* e )
{if ( (int)e->type() != Reparent )return;ReparentEvent* re = (ReparentEvent*)e;SUIT_ViewWindow* wid = ::qobject_cast<SUIT_ViewWindow*>( re->object() );if ( wid ){bool invis = wid->testAttribute( Qt::WA_WState_ExplicitShowHide ) &&wid->testAttribute( Qt::WA_WState_Hidden );// The following line is a workaround to avoid showing view window as a top-level window// before re-parenting it to workstack (issue #23467).// See SUIT_ViewWindow::setVisible() and SUIT_Desktop::childEvent().wid->setProperty("blockShow", false);addWindow( wid );wid->setVisible( !invis );}
}
Refs. from?QObject::customEvent(QEvent *event)?
This event handler can be reimplemented in a subclass to receive custom events. Custom events are user-defined events with a type value at least as large as the?QEvent::User?item of the?QEvent::Type?enum, and is typically a?QEvent?subclass. The event is passed in the?event?parameter.?
/*! Constructor.*/
SUIT_ViewWindow::SUIT_ViewWindow( SUIT_Desktop* theDesktop ): QMainWindow( theDesktop ), myManager( 0 ), myIsDropDown( true ), mySyncAction( 0 )
{myDesktop = theDesktop;setWindowIcon( myDesktop ? myDesktop->windowIcon() : QApplication::windowIcon() );setAttribute( Qt::WA_DeleteOnClose );myToolMgr = new QtxActionToolMgr( this );setProperty( "VectorsMode", false );
}
網絡
QChildEventhttps://doc.qt.io/qt-6/qchildevent.html
QObject::childEvent(QChildEvent* event)https://doc.qt.io/qt-6/qobject.html#childEvent
QObject::customEvent(QEvent *event)https://doc.qt.io/qt-6/qobject.html#customEvent
SALOME源碼分析:GUI模塊https://blog.csdn.net/qq_26221775/article/details/127759145?spm=1001.2014.3001.5502
SALOME源碼分析: GUI模塊主要組件https://blog.csdn.net/qq_26221775/article/details/148845050?spm=1001.2014.3001.5502