Signals from within the paint event -- crash?



  • If I try to call the main window's status bar's "showMessage" function (directly or via propagated signals-slots) from within another widget's paint function (a QGraphicsItem, in this case), I get an access violation deep within the Qt code, somewhere under sendSpontaneousEvent.

    I can do this from other event handlers, e.g.: mouse hover. I can also cause an output message in an widget to be displayed ,but this occurs using an internal postEvent call within that widget.

    Is there something I'm fundamentally misunderstanding about events? I want to be able to update a data model structure from WITHIN the paint event (it's the most convenient place to perform a mouse position calculation) and have other widgets update (eventually) to reflect that change.

    Is this not possible?



  • On the off chance it is helpful to anyone, a sample of the call stack:

    Qt5Guid.dll!QRasterPaintEngine::transformChanged() Line 947 + 0x3 bytes C++
    Qt5Guid.dll!QPainterPrivate::updateMatrix() Line 663 C++
    Qt5Guid.dll!QPainter::setWorldTransform(const QTransform & matrix, bool combine) Line 8232 C++
    Qt5Widgetsd.dll!QGraphicsDropShadowEffect::draw(QPainter * painter) Line 1067 C++
    Qt5Widgetsd.dll!QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem * item, QPainter * painter, const QTransform * const viewTransform, QRegion * exposedRegion, QWidget * widget, double parentOpacity, const QTransform * const effectTransform) Line 4779 C++
    Qt5Widgetsd.dll!QGraphicsScenePrivate::drawItems(QPainter * painter, const QTransform * const viewTransform, QRegion * exposedRegion, QWidget * widget) Line 4667 + 0x3c bytes C++
    Qt5Widgetsd.dll!QGraphicsView::paintEvent(QPaintEvent * event) Line 3531 C++
    Qt5Widgetsd.dll!QWidget::event(QEvent * event) Line 8118 C++
    Qt5Widgetsd.dll!QFrame::event(QEvent * e) Line 534 + 0xc bytes C++
    Qt5Widgetsd.dll!QAbstractScrollArea::viewportEvent(QEvent * e) Line 1194 + 0xc bytes C++
    Qt5Widgetsd.dll!QGraphicsView::viewportEvent(QEvent * event) Line 2967 C++
    Qt5Widgetsd.dll!QAbstractScrollAreaPrivate::viewportEvent(QEvent * event) Line 110 + 0x28 bytes C++
    Qt5Widgetsd.dll!QAbstractScrollAreaFilter::eventFilter(QObject * o, QEvent * e) Line 126 + 0x29 bytes C++
    Qt5Cored.dll!QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject * receiver, QEvent * event) Line 1031 + 0x15 bytes C++
    Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3518 + 0x11 bytes C++
    Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3487 + 0x10 bytes C++
    Qt5Cored.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 935 + 0x15 bytes C++

    Qt5Cored.dll!QCoreApplication::sendSpontaneousEvent(QObject * receiver, QEvent * event) Line 240 + 0x38 bytes C++
    Qt5Widgetsd.dll!QWidgetPrivate::drawWidget(QPaintDevice * pdev, const QRegion & rgn, const QPoint & offset, int flags, QPainter * sharedPainter, QWidgetBackingStore * backingStore) Line 5157 + 0x11 bytes C++
    Qt5Widgetsd.dll!QWidgetBackingStore::doSync() Line 1183 C++
    Qt5Widgetsd.dll!QWidgetBackingStore::sync() Line 1030 C++
    Qt5Widgetsd.dll!QWidgetPrivate::syncBackingStore() Line 1693 C++
    Qt5Widgetsd.dll!QWidget::event(QEvent * event) Line 8256 C++
    Qt5Widgetsd.dll!QMainWindow::event(QEvent * event) Line 1497 C++
    Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3522 + 0x11 bytes C++
    Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3487 + 0x10 bytes C++
    Qt5Cored.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 935 + 0x15 bytes C++
    Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 237 + 0x39 bytes C++
    Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1539 + 0xd bytes C++
    Qt5Cored.dll!QCoreApplication::sendPostedEvents(QObject * receiver, int event_type) Line 1397 + 0x11 bytes C++
    Qt5Widgetsd.dll!QGraphicsViewPrivate::dispatchPendingUpdateRequests() Line 202 + 0x17 bytes C++
    Qt5Widgetsd.dll!QGraphicsScenePrivate::_q_processDirtyItems() Line 508 + 0x20 bytes C++
    Qt5Widgetsd.dll!QGraphicsScene::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int id, void * * a) Line 177 + 0xf bytes C++
    Qt5Cored.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 487 + 0x1d bytes C++
    Qt5Cored.dll!QObject::event(QEvent * e) Line 1242 C++
    Qt5Widgetsd.dll!QGraphicsScene::event(QEvent * event) Line 3478 + 0x10 bytes C++
    Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3522 + 0x11 bytes C++
    Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 2975 + 0x10 bytes C++
    Qt5Cored.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 935 + 0x15 bytes C++
    Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 237 + 0x39 bytes C++
    Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1539 + 0xd bytes C++
    Qt5Cored.dll!QCoreApplication::sendPostedEvents(QObject * receiver, int event_type) Line 1397 + 0x11 bytes C++
    qwindowsd.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 88 + 0xa bytes C++
    Qt5Cored.dll!qt_internal_proc(HWND
    * hwnd, unsigned int message, unsigned int wp, long lp) Line 423 C++



  • Is this multithreaded application ? Is this update happening across threads ?



  • It is not multithreaded, no.



  • Does the app still crash if there is no connection to that signal? If so your signal may result in a repaint wich emits a signal which results in a repaint which em.... (google rekursion)


  • Moderators

    Hi, I don't know the exact mechanism of the crash, but try making the connection specifying Qt::QueuedConnection. That will delay the showMessage() call and hopefully avoid a crash.



  • The app will crash with or without a connected signal. What I mean is: if I directly call the member showMessage on the status bar (after confirming no stupid pointer mistakes or anything) it will crash in almost the exact manner as if I'd connected signal/slots from painted widget to the model and from the model to the main window (which would then update the status bar).

    I can make the same calls (or signals) safely from other event handles (e.g.: mouse move) but NOT from within the paint event handler.

    I can re-design architecture around this, but I'm mostly concerned that I don't understand why it's happening, and I'm concerned I will run into other issues if I don't understand the limitations on being in the paint event (or similar?) context.



  • Would you mind sharing the code? It should not happen anything by only emitting a signal in the paintEvent() method.


  • Moderators

    [quote author="AllenMSaunders" date="1406812060"]The app will crash with or without a connected signal. What I mean is: if I directly call the member showMessage on the status bar (after confirming no stupid pointer mistakes or anything) it will crash in almost the exact manner as if I'd connected signal/slots from painted widget to the model and from the model to the main window (which would then update the status bar).[/quote]That's because, when you use a Direct Connection, emitting a signal to run a slot is the same as directly calling the slot.

    That's why I suggested trying a Queued Connection.

    [quote author="NetZwerg" date="1406812601"]Would you mind sharing the code? It should not happen anything by only emitting a signal in the paintEvent() method.[/quote]
    EDIT: Oops, I thought AllenMSaunde wrote the line above. That's why my original reply below sounds odd.

    Sure. Just add "Qt::QueuedConnection" to the end of your existing connection:
    @
    connect(this, SIGNAL(mySignal(QString)),
    statusBar, SLOT(showMessage(QString)),
    Qt::QueuedConnection);
    @

    I agree that it shouldn't happen, and I don't think you've misunderstood something. The reality is that Qt is a huge and complex framework so there will be bugs.

    I suspect that, somewhere deep inside Qt's code, something falls over when you interrupt the current paint event with an action that will also update your GUI's display. In your case, showMessage() interrupts the current paint event.

    If this indeed is the source of the bug, then using a Queued Connection is a workaround for the crash, as it waits for the current paint event to finish first, before updating the status bar.

    If that does eliminate the crash, you can bring this to the attention of Qt engineers by reporting it to https://bugreports.qt-project.org/



  • Also very keen to make this happen. How about sharing simple sample code so that we can see the same ?



  • The code is pretty large and the relevant components are scattered.

    When I get a chance I'll try to trim it down to the minimum components that produce the behavior.

    Thanks all for the responses so far.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.