c++qtqwidgetqt6

How do I force a QWidget to be repainted?


Given the following main window implementation:

#include <QApplication>

#include "MainWindow.h"

namespace ui {
MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        child(this) {
    this->resize(425, 450);
    this->child.move(10, 10);
    this->child.resize(400, 400);
}

MainWindow::~MainWindow() {}

void MainWindow::showEvent(QShowEvent* event) {
    QWidget::showEvent(event);

    qDebug() << "Updating.";
    this->child.update();
    this->child.update();
    this->child.update();
    this->child.update();
    this->child.repaint();
    this->child.repaint();
    this->child.repaint();
    this->child.repaint();
    QApplication::processEvents();
} 
}  // namespace ui

and the widget which looks like this:

#include <QPainter>

#include "Widget.h"

namespace ui {
Widget::Widget(QWidget *parent) :
        QWidget(parent) { }

void Widget::paintEvent(QPaintEvent *event) {
    qDebug() << "paintEvent called.";
    QWidget::paintEvent(event);
}
}  // namespace ui

I would expect to see at least four (and possibly more than eight) “paintEvent called.” messages in the console. However, the console just shows:

Updating.
paintEvent called.
paintEvent called.

The output is exactly the same if I remove all the this->child.update() and this->child.repaint() calls in MainWindow.cpp.

If update() and repaint() don't actually update or repaint a widget, what should I do instead in order to force a redraw of a widget?


Solution

  • Qt expects your paintEvent() method to be idempotent -- i.e. it shouldn't make any difference how many times it is called, since given the same widget-state, it should always draw the same graphic image onto the widget's screen-area.

    Therefore, the expectation is that your code will call update() whenever something has changed that might require a modification to your widget's appearance, and Qt will make sure that paintEvent() is called ASAP after that, ideally just once (even if you called update() more than once).

    There should never be any need for you to call repaint() explicitly.

    You don't say so explicitly, but my spidey-sense tells me that you may be trying to work around a problem where a function called inside your main/GUI thread is taking a long time to return, and that is causing your GUI not to be updated in a timely manner.

    If that is the case, then the proper solution would be to either make that routine return faster, or (if that isn't possible) to move it out into a separate thread so that it can execute asynchronously and not block the GUI thread while it runs. Functions called by the main/GUI thread in Qt should always return quickly, otherwise GUI updates will get held off, resulting in a poor user-experience.