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?