本文记录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