0

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?

6
  • 1
    You would certainly not see separate paint event calls for each subsequent call to update(), as the documentation clearly says: "This function does not cause an immediate repaint; instead it schedules a paint event for processing when Qt returns to the main event loop [...] Calling update() several times normally results in just one paintEvent() call." It's normally not necessary to manually request repaints, are you asking this out of interest of the Qt behavior, or is this the resulting question caused by a different problem? Commented Jul 7 at 23:18
  • From what I understood, consecutive calls to update do get optimized, but not the calls to repaint, but I don't find the source any longer. An I wrong? Regarding your question, this is the resulting question caused by a different problem, which is yet too large to be posted in its current state to a Q&A site. Trying to simplify it, I came to the observation that a given widget in an app is not redrawn when expected, and I was wondering why adding extra calls to force a repaint had no effect. Commented Jul 7 at 23:26
  • 2
    » at some moment in the future. I know that this is true at least on X11, I don't really know the background of Wayland and other OS. To summarize, calling repaint() multiple times in showEvent() may not be effective as you may believe, and you should eventually do a more appropriate test by calling a function that does that, triggered by a QTimer.singleShot launched in the showEvent() instead. In any case, this seems more an XY problem. It should almost never be necessary to call repaint(), and if it didn't work in your case it may not be related » Commented Jul 7 at 23:43
  • 1
    » to the case you're proposing (considering the above, you may just happen to reproduce a similar issue, but just coincidentally). I'd suggest you to take your time and devise a proper minimal reproducible example based on your real issue. I know it may be difficult, but it would be more appropriate than getting an answer to a question that may end up being unrelated to your problem, thus not solving it in reality. Commented Jul 7 at 23:46
  • 1
    I have hardly ever had to call update() and absolutely never had to call repaint(), let alone doing so in methods such as showEvent()/paintEvent(). This example is going to look a bit too weird for people to be able to figure out a solution to whatever you are trying to do. I concur with @musicamante that it looks like your real problem is something else and most likely will be more relatable to us.
    – Atmo
    Commented Jul 8 at 1:11

1 Answer 1

2

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.