Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QWidget constructor triggers processEvents (on Windows)?



  • I was experiencing a bug in my application that did not make much sense to me, and finally tracked it down.

    What was happening:
    This piece of code is executed in a dialog, in response to some signal. This entirely happens in the GUI thread. There are other threads working, but in no way could they be inducing a bug in this small piece of code (or so I thought...)
    @CurrentObject = new Object; // CurrentObject is a member of this class
    Q_ASSERT(CurrentObject);

        if (CurrentOperator)
        {
            //Create a widget instance
            Q_ASSERT(!CurrentObjectWidget);
    
             //Virtual method that returns a new QWidget subclass
            CurrentObjectWidget = CurrentObject->CreateConfigurationWidget(this);
    
            if (CurrentObjectWidget)
            {
                 Q_ASSERT(CurrentObject); //<<<< CurrentObject sometimes becomes null here?!?!?!
    

    @

    I tracked the bug down by watching when CurrentObject got modified. And to my surprise, it turns out that the constructor of QWidget seems to trigger a processEvents (or something equivalent), which makes it process some pending events, one of which triggers another signal that clears CurrentObject.

    Here's the call stack I got:
    @
    [ That particular message is forwarded to my dialog and happens to reset some data ]
    ....exe!...::...::OnMsgRefreshClientGui(unsigned int, long) Line 1428 C++
    mfc100ud.dll!CWnd::OnWndMsg(unsigned int, unsigned int, long, long *) Line 2383 C++
    ...
    mfc100ud.dll!AfxWndProcBase(HWND__ *, unsigned int, unsigned int, long) Line 420 C++
    user32.dll!75d062fa()
    user32.dll!75d06d3a()
    ...
    user32.dll!75d160dc()
    QtWinMigrate_x86_d4.dll!QMfcApp::winEventFilter(tagMSG *, long *) Line 414 C++
    QtCore_x86_d4.dll!QCoreApplication::filterEvent(void *, long *) Line 2510 C++
    QtGui_x86_d4.dll!QtWndProc(HWND__ *, unsigned int, unsigned int, long) Line 1484 C++
    user32.dll!75d062fa()
    user32.dll!75d07316()
    user32.dll!75d06ce9()
    user32.dll!75d06de8()
    user32.dll!75d0a740()
    ntdll.dll!7796010a()
    user32.dll!75d0a95d()
    user32.dll!75d0a8e8()
    user32.dll!75d0aa3c()
    user32.dll!75d08a5c() //CreateWindowEx
    QtGui_x86_d4.dll!QWidgetPrivate::create_sys(HWND__ *, bool, bool) Line 452 C++
    QtGui_x86_d4.dll!QWidget::create(HWND__ *, bool, bool) Line 1490 C++
    QtGui_x86_d4.dll!QWidgetPrivate::createWinId(HWND__ *) Line 2518 C++
    QtGui_x86_d4.dll!QWidgetPrivate::setParent_sys(QWidget *, QFlags<enum Qt::WindowType>) Line 648 C++
    QtGui_x86_d4.dll!QWidget::setParent(QWidget *, QFlags<enum Qt::WindowType>) Line 10098 C++
    QtGui_x86_d4.dll!QWidgetPrivate::init(QWidget *, QFlags<enum Qt::WindowType>) Line 1345 C++
    QtGui_x86_d4.dll!QWidget::QWidget(QWidget *, QFlags<enum Qt::WindowType>) Line 1155 C++
    ....dll!...::...::CreateConfigurationWidget(QWidget *) Line 128 C++
    ...
    QtGui_x86_d4.dll!QTreeWidget::setCurrentItem(QTreeWidgetItem *) Line 2803 C++
    ....dll!...::...::RefreshOperatorList(QTreeWidgetItem *, ...) Line 895 C++
    ...
    ....dll!...::...::DoReset() Line 1584 C++
    ....dll!...::...::qt_metacall(QMetaObject::Call, int, void * *) Line 203 C++
    ...
    QtGui_x86_d4.dll!QAbstractButton::clicked(bool) Line 204 C++
    [...]
    @
    As you can see, the click triggers a refresh, where I call the CreateConfigurationWidget method, which constructs a QWidget... but then it goes deep in low level methods, and then it processes some window message, which was really not expected.

    It's this call in QWidgetPrivate::create_sys that seems to trigger a processing of the pending events:
    @id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()),
    reinterpret_cast<const wchar_t *>(title.utf16()), style,
    data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(),
    parentw, NULL, appinst, NULL);@

    Is this expected behavior? That means everytime I create a widget, I'd have to expect that external messages that can affect my object will be processed at that point?
    Is there any way to avoid this?


Log in to reply