Unable to paint on Qt Widget, shows error “paintEngine: Should no longer be called”



  • I have created a widget using Qt Creator such a way that it has two sub windows inside a main window and some push buttons to load, save images, set pen width and color to paint on the window. But when i start to paint it gives me error saying

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

    Does anyone know what mistake i am doing, i checked threads related to this topic but could not find suitable solution. I am also new to c++, so please help me to find a solution

    This is my code below

    widget.h

    #define WIDGET_H
    
    #include <QWidget>
    #include <QtCore>
    #include <QImage>
    #include <QColor>
    #include <QPoint>
    #include <QtGui>
    #include <QPainter>
    #include <QMainWindow>
    #include <QFileDialog>
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
        bool isModified() const { return modified; }
        QColor penColor() const { return newPenColor; }
        int penWidth() const { return newPenWidth; }
    
    
    protected:
        void paintEvent(QPaintEvent *event);
        void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    
    private slots:
        void on_open_clicked();
    
        void on_save_clicked();
    
        void on_penWidth_clicked();
    
        void on_penColor_clicked();
    
    private:
        Ui::Widget *ui;
    
        QImage image;
        QPixmap imageobject;
        int newPenWidth;
        QColor newPenColor;
        bool modified;
        bool scribbling;
        QPoint firstPoint, secondPoint;
        void drawFirstPoint(const QPoint);
        void drawSecondPoint(const QPoint);
    };
    
    #endif // WIDGET_H
    

    main.cpp

    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    

    widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    #include <QtWidgets>
    #ifndef QT_NO_PRINTER
    #include <QtPrintSupport/QPrinter>
    #include <QtPrintSupport/QPrintDialog>
    #endif
    #include <QLabel>
    #include <QWidget>
    
    
    Widget::Widget(QWidget *parent) : QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        setAttribute(Qt::WA_StaticContents);
        modified = false;
        scribbling = false;
        newPenWidth = 1;
        newPenColor = Qt::blue;
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::on_open_clicked()
    {
        QString filename = QFileDialog::getOpenFileName(this, tr("choose"), "", tr("Image(*.png *.jpg *.jpeg *.bmp *.gif)"));
           if (QString::compare(filename, QString())!=0)
           {
               QImage image;
               bool valid = image.load(filename);
               if (valid)
               {
                   image = image.scaledToWidth(ui->inputWindow->width(), Qt::SmoothTransformation);
                   ui->inputWindow->setPixmap(QPixmap::fromImage(image));
    
                   image = image.scaledToWidth(ui->outputWindow->width(), Qt::SmoothTransformation);
                   ui->outputWindow->setPixmap(QPixmap::fromImage(image));
               }
               else
               {
                   //Error handling
               }
           }
    }
    
    void Widget::on_save_clicked()
    {
        QString filename = QFileDialog::getSaveFileName(this,tr("choose"), "", tr("PNG (*.png);; JPEG (*.jpg *.jpeg);; BMP(*.bmp);; GIF(*.gif)"));
    
        QImage imageobject = image;
        imageobject.save(filename);
    
    }
    
    void Widget::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        QRect dirtyRect = event->rect();
        painter.drawImage(dirtyRect, image, dirtyRect);
    }
    
    void Widget::mousePressEvent(QMouseEvent *event)
    {
        scribbling = true;
        if (event->button() == Qt::LeftButton && scribbling)
        {
            firstPoint = event->pos();
            drawFirstPoint(firstPoint);
        }
        else if (event->button() == Qt::RightButton && scribbling) {
                 secondPoint = event->pos();
                 drawSecondPoint(secondPoint);
    
        }
    }
    
    void Widget::drawFirstPoint(const QPoint)
    {
        QPainter painter(this);
        painter.setPen(QPen(newPenColor, newPenWidth, Qt::SolidLine, Qt::RoundCap,
                            Qt::RoundJoin));
    
        painter.drawPoint(firstPoint);
        modified = true;
        int rad = (newPenWidth / 2) + 2;
        update(QRect(firstPoint, firstPoint).normalized().adjusted(-rad, -rad, +rad, +rad));
    }
    
    void Widget::drawSecondPoint(const QPoint)
    {
        QPainter painter(this);
        painter.setPen(QPen(newPenColor, newPenWidth, Qt::SolidLine, Qt::RoundCap,
                            Qt::RoundJoin));
    
        painter.drawPoint(secondPoint);
        modified = true;
        int rad = (newPenWidth / 2) + 2;
        update(QRect(secondPoint, secondPoint).normalized().adjusted(-rad, -rad, +rad, +rad));
    }
    
    void Widget::on_penWidth_clicked()
    {
        bool ok;
        int newWidth = QInputDialog::getInt(this, tr("Scribble"),
                                            tr("Select pen width:"),
                                            this->penWidth(), 1, 50, 1, &ok);
        if (ok)
            newPenWidth = newWidth;
    }
    
    void Widget::on_penColor_clicked()
    {
        QColor newColor = QColorDialog::getColor(this->penColor());
        if (newColor.isValid())
            newPenColor = newColor;
    }
    

    widget.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>Widget</class>
     <widget class="QWidget" name="Widget">
      <property name="enabled">
       <bool>true</bool>
      </property>
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>1300</width>
        <height>700</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Test window</string>
      </property>
      <property name="layoutDirection">
       <enum>Qt::LeftToRight</enum>
      </property>
      <widget class="QLabel" name="inputWindow">
       <property name="geometry">
        <rect>
         <x>40</x>
         <y>120</y>
         <width>600</width>
         <height>500</height>
        </rect>
       </property>
       <property name="maximumSize">
        <size>
         <width>600</width>
         <height>16777215</height>
        </size>
       </property>
       <property name="cursor">
        <cursorShape>CrossCursor</cursorShape>
       </property>
       <property name="text">
        <string>TextLabel</string>
       </property>
      </widget>
      <widget class="QLabel" name="outputWindow">
       <property name="geometry">
        <rect>
         <x>660</x>
         <y>120</y>
         <width>600</width>
         <height>500</height>
        </rect>
       </property>
       <property name="maximumSize">
        <size>
         <width>600</width>
         <height>16777215</height>
        </size>
       </property>
       <property name="text">
        <string>TextLabel</string>
       </property>
      </widget>
      <widget class="QWidget" name="layoutWidget">
       <property name="geometry">
        <rect>
         <x>170</x>
         <y>10</y>
         <width>651</width>
         <height>31</height>
        </rect>
       </property>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <widget class="QPushButton" name="open">
          <property name="cursor">
           <cursorShape>PointingHandCursor</cursorShape>
          </property>
          <property name="text">
           <string>OPEN</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="save">
          <property name="cursor">
           <cursorShape>PointingHandCursor</cursorShape>
          </property>
          <property name="text">
           <string>SAVE</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="penWidth">
          <property name="text">
           <string>Pen Width</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="penColor">
          <property name="text">
           <string>Pen Color</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="pushButton_5">
          <property name="text">
           <string>PushButton</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    

  • Moderators

    You are calling drawFirstPoint and drawSecondPoint from within mousePressEvent. Don't do that. The only place you should create and use a painter is inside paintEvent. Instead of drawing from mouse event store the data to draw (the position and which button was pressed) and call update(). This will schedule a paint event, inside of which you can check the data and paint what's needed.

    Btw:

    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    

    Be consistent. If you use Q_DECL_OVERRIDE on one override (good!), use it on all of them.



  • @Chris-Kawa Thanks for the suggestion, i am inspired from the qt example scribble in doing my program, in that example the painter is created and used in drawLineTo and updated. Do you know how that works?

    I also tried to modify my program accordingly as you said but its getting complicated for me, maybe i am doing mistakes.

    One more question, what is the difference in these two below errors?

    QPainter::begin: Paint device returned engine == 0, type: 3
    

    and

    QPainter::begin: Paint device returned engine == 0, type: 1
    

  • Qt Champions 2016

    hi
    The Scribble example draws to a image

    void ScribbleArea::drawLineTo(const QPoint &endPoint)
    {
    QPainter painter(&image); << to image
    ...
    }

    and then it paints that image in paint
    void ScribbleArea::paintEvent(QPaintEvent *event)
    {
    QPainter painter(this);
    QRect dirtyRect = event->rect();
    painter.drawImage(dirtyRect, image, dirtyRect); << draw image
    }

    To avoid drawing whole picture each time, it uses the event->rect();
    that tells which area need repainting.
    This are is set by drawLineTo.



  • @mrjj thanks for your kind reply, I understood what you explained and wanted to try the scribble example. I made a test program to check the scribble example by using Qt Widget creator. I made widget using ui class and the inside code is completely from scribble example but modified. This time i am getting the error as

    QPainter::begin: Paint device returned engine == 0, type: 3
    

    Can you please find the problem. This is my code

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "inputwindow.h"
    #include "outputwindow.h"
    #include <QFileDialog>
    #include <QInputDialog>
    #include <QColorDialog>
    #include <QtGui>
    #include <QtCore>
    #include <QPoint>
    #include <QImage>
    
    namespace Ui {
    class MainWindow;
    class Inputwindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
        QImage image;
        QColor penColor() const { return newPenColor; }
        int penWidth() const { return newPenWidth; }
    
    public slots:
    
    private slots:
        void on_open_clicked();
    
        void on_penwidth_clicked();
    
        void on_pencolor_clicked();
    
    private:
        Ui::MainWindow *ui;
        Inputwindow *inputwindow;
        int newPenWidth;
        QColor newPenColor;
    };
    
    #endif // MAINWINDOW_H
    

    inputwindow.h

    #ifndef INPUTWINDOW_H
    #define INPUTWINDOW_H
    
    #include <QWidget>
    #include <QHBoxLayout>
    
    namespace Ui {
    class Inputwindow;
    }
    
    class Inputwindow : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Inputwindow(QWidget *parent = 0);
        ~Inputwindow();
        QImage image;
        bool open(const QString &fileName);
        bool isModified() const { return modified; }
        QColor penColor() const { return newPenColor; }
        int penWidth() const { return newPenWidth; }
    
    protected:
        void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
        void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
        void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
        void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    
    private slots:
    
    private:
        Ui::Inputwindow *ui;
    
        bool modified;
        bool scribbling;
        QPoint lastPoint;
        int newPenWidth;
        QColor newPenColor;
        void drawLineTo(const QPoint &endPoint);
    };
    
    #endif // INPUTWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "inputwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        //setCentralWidget(inputwindow);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    
    void MainWindow::on_open_clicked()
    {
        QString fileName = QFileDialog::getOpenFileName(this, tr("choose"), "", tr("Image(*.png *.jpg *.jpeg *.bmp *.gif)"));
           if (QString::compare(fileName, QString())!=0)
           {
                   inputwindow = new Inputwindow(this);
                   inputwindow->setGeometry(QRect(QPoint(10,50),QSize(690,400)));
                   inputwindow->open(fileName);
                   inputwindow->show();
    
           }
    }
    
    void MainWindow::on_penwidth_clicked()
    {
        bool ok;
        int newWidth = QInputDialog::getInt(this, tr("Scribble"),
                                            tr("Select pen width:"),
                                            this->penWidth(), 1, 50, 1, &ok);
        if (ok)
            newPenWidth = newWidth;
    }
    
    void MainWindow::on_pencolor_clicked()
    {
        QColor newColor = QColorDialog::getColor(this->penColor());
        if (newColor.isValid())
            newPenColor = newColor;
    }
    

    inputwindow.cpp

    #include "inputwindow.h"
    #include "ui_inputwindow.h"
    #include <QtWidgets>
    
    Inputwindow::Inputwindow(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Inputwindow)
    {
        ui->setupUi(this);
        setAttribute(Qt::WA_StaticContents);
        modified = false;
        scribbling = false;
        newPenWidth = 1;
        newPenColor = Qt::blue;
    }
    
    Inputwindow::~Inputwindow()
    {
        delete ui;
    }
    
    bool Inputwindow::open(const QString &fileName)
    {
        QImage image;
        bool valid = image.load(fileName);
        if (valid)
        {
        image = image.scaledToWidth(ui->label->width(), Qt::SmoothTransformation);
        ui->label->setPixmap(QPixmap::fromImage(image));
        update();
        return true;
        }
        else
        {
            //Error handling
        }
    }
    
    
    
    void Inputwindow::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        QRect dirtyRect = event->rect();
        painter.drawImage(dirtyRect, image, dirtyRect);
    }
    
    void Inputwindow::mousePressEvent(QMouseEvent *event)
    {
        scribbling = true;
        if (event->button() == Qt::LeftButton) {
            lastPoint = event->pos();
            scribbling = true;
        }
    }
    
    void Inputwindow::mouseMoveEvent(QMouseEvent *event)
    {
        if ((event->buttons() & Qt::LeftButton) && scribbling)
            drawLineTo(event->pos());
    }
    
    void Inputwindow::mouseReleaseEvent(QMouseEvent *event)
    {
        if (event->button() == Qt::LeftButton && scribbling) {
            drawLineTo(event->pos());
            scribbling = false;
        }
    }
    
    void Inputwindow::drawLineTo(const QPoint &endPoint)
    {
        QPainter painter(&image);
        painter.setPen(QPen(newPenColor, newPenWidth, Qt::SolidLine, Qt::RoundCap,
                            Qt::RoundJoin));
        painter.drawLine(lastPoint, endPoint);
        modified = true;
    
        int rad = (newPenWidth / 2) + 2;
        update(QRect(lastPoint, endPoint).normalized()
                                         .adjusted(-rad, -rad, +rad, +rad));
        lastPoint = endPoint;
    }
    

  • Qt Champions 2016

    @beginMyCoding said:

    drawLineTo

    There you use image variable.
    Where is image created/set a size for the image.
    This error could be due to image having no size.
    Im not sure its the case, but easy to test
    could you try qDebug() <<"img:" << image.isNull() ;



  • @mrjj said:

    qDebug() <<"img:" << image.isNull() ;

    where should i test that function? In inputWindow?



  • @mrjj I created a widget window (inputwindow) to load image and use painter to draw on that image


  • Qt Champions 2016

    @beginMyCoding
    Im still not 100% sure u set the image

    you have defined in
    class Inputwindow : public QWidget
    {
    public:
    QImage image; <<<< -- this one is used in Inputwindow::drawLineTo
    xxx

    and you do in Inputwindow::open
    ui->label->setPixmap(QPixmap::fromImage(image));
    but this "image" is local variable.
    so that is a Label having the image and the "other image " frm .h is not used. ?

    or does the massive scrolling confuse my brain ?

    --
    qDebug() <<"img:" << image.isNull() ;
    in paintevent



  • @mrjj said:

    qDebug() <<"img:" << image.isNull() ;

    This is what i am getting when i use

    qDebug() <<"img:" << image.isNull() ;

    in paintEvent

    img: true
    img: true
    img: true
    img: true
    img: true
    img: true
    img: true
    img: true
    QPainter::begin: Paint device returned engine == 0, type: 3
    QPainter::setPen: Painter not active
    img: true
    img: true
    img: true
    

  • Moderators

    As @mrjj already said you load your image into a local variable in open():

    bool Inputwindow::open(const QString &fileName)
    {
        QImage image; <-- this one is not the one you use later!
        bool valid = image.load(fileName);
        if (valid)
        {
        image = image.scaledToWidth(ui->label->width(), Qt::SmoothTransformation);
        ui->label->setPixmap(QPixmap::fromImage(image));
        update();
        return true;
        }
        else
        {
            //Error handling
        }
    }
    

    That means your QImage image in InputWindow is not set! Remove this line in open():

    QImage image;
    


  • @jsulm Hi
    Thanks for you reply..
    I removed the line QImage image as you mentioned. I got rid of the errors but its not painting if i try to paint on the Image. I wanted to paint on the image loaded in inputwindow.
    Do you know what mistake i am making?


  • Qt Champions 2016

    Hi
    Maybe the label is covering up the image.

    ui->label->setPixmap(QPixmap::fromImage(image));

    This shows a copy of the image on screen. (not the one u draw on)
    Try to remove it and see if that makes difference.



  • @mrjj yeah!! its working bro if i remove label.. Thank you all for your suggestions



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.