qt 5 how to prevent repaint whole window if i want repaint only 1 widget

Viewed 31

Minimal code example:

class Boo : public QPushButton{
public:
    Boo(QWidget* w) : QPushButton(w){}
    virtual void paintEvent(QPaintEvent* ev){
        qDebug()<<__FUNCTION__<<this->objectName();
    }
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    virtual void paintEvent(QPaintEvent* ev){
        qDebug()<<__FUNCTION__;
    }

private:
    QTimer t;
    Ui::MainWindow *ui;
    Boo *b1, *b2;
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    b1 = new Boo(this);
    b1->setObjectName("O1");
    b2 = new Boo(this);
    b2->setObjectName("O2");
    connect(&t, &QTimer::timeout, this, [this](){
         b2->repaint();
     });
    t.start();
    t.setInterval(10);
}

Outputs infinitely: MainWindow::paintEvent Boo::paintEvent "O1" Boo::paintEvent "O2"

but i call repaint only for button b2. Using "QWidget::repaint(int x, int y, int w, int h)" or :QWidget::update()" also invoke repaint for main window.

Problem exists on Qt5.12/5.15 and windows11, but looks like general qt bug.

This issue cause high GPU consumption in our more complex GUI application.

Ok. I found the reason myself, after add:

...
b1->setGeometry(15,15, 12, 12);
...
b2->setGeometry(35,35, 14, 14);
...
 virtual void paintEvent(QPaintEvent* ev){
        qDebug()<<__FUNCTION__<<ev->rect();
    }

ouput says, that actual repaint is done only for button region:

MainWindow::paintEvent QRect(35,35 14x14) Boo::paintEvent "O2" QRect(0,0 14x14)

Important thing: ivoke setGeometry for button, not just add as child. In other case (usable only for toy example, ofcourse) repaint button with unset geometry will lead to repaint every button with unset geometry.

1 Answers

Qt repaints by default all parents too, to allow widgets being partially transparent. If Qt doesn't repaint the parent on an update, some pixels of the previous paintEvent may still be visible.

Qt provides two methods to optimise this behaviour when no transparent background is needed:

More information

Related