GracefulCamel
GracefulCamel

Reputation: 48

Can't use QPainter in paintEvent of custom QWidget (Qt5)

The error in question is as follows:

QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
QPainter::setFont: Painter not active

After looking at a ton of online forum posts that all came down to people making the same mistake of trying to paint on their widgets outside of paintEvent(), I've been unable to have any luck. I tried drawing directly on this custom QWidget subclass, I've tried making a child QWidget and drawing on that. Can someone please show me what thing I'm (probably obviously to someone else) doing wrong?

Thanks in advance.

Header:

#ifndef TEXTDISPLAY_H
#define TEXTDISPLAY_H

#include <QWidget>

class TextDisplay : public QWidget
{
    Q_OBJECT

public:
    TextDisplay(QString text, QString fontFamily = "Helvetica", int fontSize = 20,
                int fontColor = Qt::black, QWidget* parent = 0);

protected:
    void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
    void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;

private:
    QString text;
    QString fontFamily;
    int fontSize;
    int fontColor;
};

#endif // TEXTDISPLAY_H

Cpp:

#include "textdisplay.h"
#include <QPainter>


TextDisplay::TextDisplay(QString text, QString fontFamily, int fontSize,
                         int fontColor, QWidget* parent)
    : QWidget(parent), text(text), fontFamily(fontFamily),
      fontSize(fontSize), fontColor(fontColor)
{
    this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
}

void TextDisplay::resizeEvent(QResizeEvent*) {
    paintEvent(NULL);
}

void TextDisplay::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setPen(fontColor);
    painter.setFont(QFont(fontFamily, fontSize));

    QRect rect(QPoint(0, 0), this->size());
    QRect bound;
    QTextOption options;
    options.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);

    painter.drawText(rect, Qt::TextWordWrap | Qt::TextWrapAnywhere, text, &bound);

    this->setMinimumHeight(bound.size().height());
}

Edit with solution:

Thanks to both responders - I needed to do two things to get it working:

a) Get rid of paintEvent(NULL). I got rid of the resizeEvent override as well, it was unnecessary as suggested.

b) Set a minimum size for the widget. Without this, the paintEvent was never called by Qt.

Upvotes: 2

Views: 2956

Answers (1)

peppe
peppe

Reputation: 22724

If you want to schedule a redraw for your widget, just call update().

If you need an immediate repaint (which you almost never need) you can call repaint() instead.

Calling paintEvent() directly will not work -- Qt needs to prepare the backing store to handle the painting, so you can't bypass the update mechanism. Instead, call the methods above, which will result in a call to paintEvent() (if the widget is visibile, not occluded, etc.etc.etc.).

Note also that you should not need to reimplement resizeEvent() just to update your widget. That should already be done for you by Qt...

Upvotes: 3

Related Questions