QMainWindow stops receiving QEvent::UpdateRequest when user opens menu or resizes window

2.3k views Asked by At

MyWindow which inherits from QMainWindow. MyWindow contains a QGLWidget that displays an animation.

The problem is that the animation pauses whenever I open a menu or resize the window.

The animation is implemented by calling QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)) periodically, then calling redrawing each time the window receives the QEvent::UpdateRequest, like this:

bool MyWindow::event(QEvent *event)
{
    qDebug() << event;
    switch (event->type())
    {
        case QEvent::UpdateRequest:
            render();
            return true;
        default:
            return QMainWindow::event(event);
    }
}

As seen from qDebug(), while a menu is open or the window is being resized, the window stops receiving update request events.

Is there a setting on QMainWindow/QWidget to make it continue to receive update request events? Or is there some better way to implement the animation?

Edit: I'm on Mac OS X.

3

There are 3 answers

0
jlstrecker On BEST ANSWER

Since I haven't heard any more from Kuba Ober about the possibility of this being a Qt bug, I went ahead and filed a bug report: https://bugreports.qt-project.org/browse/QTBUG-33382

I was able to partially work around the problem by calling the render() function more directly — that is, instead of sending an event, receiving the event, and having the event handler call the function. I accomplished this with a dispatch queue (but not the main dispatch queue, since that's tied to the default run loop so it has the same problem). However, working with the QGLWidget on multiple threads was difficult. After trying for a while to use the moveToThread() function to make this work, and considering other factors involved in the project, I decided to use something other than Qt to display this window.

1
Kuba hasn't forgotten Monica On

This may be a Qt bug. I'll investigate.

Alas, you're way overcomplicating your code.

  1. The postEvent should be simply replaced by this->update(). Behind the scenes it posts the event for you.

  2. One can simply connect a QTimer instance's signal to widget, SLOT(update()). If you want to save on a QObject instance, use QBasicTimer and reimplement timerEvent as follows: void MyWidget::timerEvent(QTimerEvent* ev) { if (ev.timerId() == m_timer.timerId()) update(); }

  3. There's no need to deal with event() reimplementation. Simply reimplement paintEvent() - that's what it's for.

2
Ashif On

Qt GUI updates are performing on MainThread. So slow gui response is reasonable, if you have many gui functionality does at same time. So generally, do not overload MaiThread with so many heavey function calls.

Probable solution to speed up your GUI response.

  1. If PostEvent is called by your MainThread( if you are using timer from main gui thread ), instead move those to backend functionality in a worker thread and postEvent once it has been done.
    • you call QCoreApplication::processEvents(), after your render(); function in MainThread. This will help system to process all the other events that are in the event-loop before to continue

Please check, following link How to improve GUI response

Note: When creating and triggering the timer it will run within your thread by default, it wont start another thread.