c++qtqwidgetqpainterpaintevent

paintEvent not being called in custom widget


I am trying to paint a rectangle at the mouse location every time it is clicked.

Currently, the setup is as follows:

TableMaker is my main window and was mostly generated in Qt Designer.

I have subclassed a QWidget, RenderArea, and added it inside a frame in my ui.

I currently have TableMaker::mousePressEvent calling a function in renderArea that creates a new QRect and keeps a reference to it in a vector.

So far everything up to this point works, and when I check in a debugger it is indeed creating these QRects and storing them on each mouse press.

However, I tried overriding paintEvent for renderArea so that it will update and draw these new QRects, but it is never being called.

I feel like I have misunderstood how painting and the associated events work, and who should actually have ownership of the overridden paintEvent.

Below is the code for the 2 classes TableMaker and RenderArea:

main.cpp:

#include "TableMaker.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TableMaker w;
    w.show();
    return a.exec();
}

TableMaker.cpp:

#include "TableMaker.h"

TableMaker::TableMaker(QWidget *parent) : QMainWindow(parent)
{
    ui.setupUi(this);
    renderArea = new RenderArea;
    QGridLayout* drawAreaLayout = new QGridLayout;
    drawAreaLayout->addWidget(renderArea);
    ui.tentFrame->setLayout(drawAreaLayout);
}

void TableMaker::mousePressEvent(QMouseEvent* e) {
    renderArea->addNewTable(e->pos());
    renderArea->update();
}

TableMaker::~TableMaker()
{}

TableMaker.h:

#include <QtWidgets/QMainWindow>
#include <QtWidgets>
#include <QtGui>
#include "ui_TableMaker.h"
#include "RenderArea.h"

class TableMaker : public QMainWindow
{
    Q_OBJECT

public:
    TableMaker(QWidget *parent = nullptr);
    void mousePressEvent(QMouseEvent* e) override;
    ~TableMaker();

private:
    
    RenderArea* renderArea;
    QLabel* statusMsg = new QLabel;
    Ui::TableMakerClass ui;
};

renderArea.cpp:

#include "RenderArea.h"

RenderArea::RenderArea(QWidget* parent): QWidget(parent) {
    brush.setColor(tableColor);
    pen.setBrush(brush);
}

void RenderArea::addNewTable(QPoint p) {
    QRect* rec = new QRect(p, QSize(100, 100));
    recs.push_back(rec);
    this->update();
}

QSize RenderArea::sizeHint() const {
    return QSize(100, 100);
}

void RenderArea::paintEvent(QPaintEvent* e) {
    QWidget::paintEvent(e);
    QPainter p(this);
    p.setPen(pen);
    p.setBrush(brush);
    for (QRect* r : recs) {
        p.drawRect(*r);
    }
}

renderArea.h:

#include <Qtwidgets>
#include "tableWidget.h"

class RenderArea : public QWidget {

    Q_OBJECT

public:
    explicit RenderArea(QWidget* parent = nullptr);
    void addNewTable(QPoint p);

protected:
    QSize sizeHint() const override;
    void paintEvent(QPaintEvent* e) override;

private:
    QColor tableColor = QColor(0, 0, 255);
    QBrush brush;
    QPen pen;
    QVector<QRect*> recs;
};

How do paintEvents / painting work? I have tried reading the docs about QPaintEvent and it seems like I am overriding paintevent correctly.

Another post on here mentions that sizeHint must be reimplemented, but as you can see below, I have done that and it still does not work.


Solution

  • Explanation:

    paintEvent does get called, you can check that using a qDebug():

    void RenderArea::paintEvent(QPaintEvent* e)
    {
        QWidget::paintEvent(e);
    
        QPainter p(this);
    
        p.setPen(pen);
        p.setBrush(brush);
    
        //outputs: Qt::NoBrush
        qDebug()<<p.brush().style();
        //outputs: "#0000ff"
        qDebug()<<p.brush().color().name();
        //outputs: "#0000ff"
        qDebug()<<p.pen().color().name()<<"\n";
    
        for (QRect* r : recs)
        {
            //list gets bigger with every mouse press
            qDebug()<<r;
            p.drawRect(*r);
        }
    }
    

    The problem is that the rectangles are being drawn with a brush that has no style set.

    From Qt Documentation: QBrush Class:

    The brush style() defines the fill pattern using the Qt::BrushStyle enum. The default brush style is Qt::NoBrush (depending on how you construct a brush). This style tells the painter to not fill shapes.


    Solution:

    You just need a small addition to RenderArea ctor:

    RenderArea::RenderArea(QWidget* parent): QWidget(parent)
    {
        //set brush style
        brush.setStyle(Qt::SolidPattern);
        brush.setColor(tableColor);
        pen.setBrush(brush);
    }
    

    Result:

    Rectangle drawn on mouse press