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>
-
You are calling
drawFirstPoint
anddrawSecondPoint
from withinmousePressEvent
. Don't do that. The only place you should create and use a painter is insidepaintEvent
. Instead of drawing from mouse event store the data to draw (the position and which button was pressed) and callupdate()
. 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 indrawLineTo
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
-
hi
The Scribble example draws to a imagevoid 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 fromscribble
example but modified. This time i am getting the error asQPainter::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; }
-
@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() ; -
@beginMyCoding
Im still not 100% sure u set the imageyou have defined in
class Inputwindow : public QWidget
{
public:
QImage image; <<<< -- this one is used in Inputwindow::drawLineTo
xxxand 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
-
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 lineQImage 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? -
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.