Qt: QWidget :: paintEngine: no longer needs to be called

I am trying to create an application that can draw with my finger on a canvas.
To do this, I will subclass QWidget

as MFCanvas

, registered the class in QML with
qmlRegisterType<>()

, implementing a virtual function paintEvent();

, and
relying on it with QPainter

inside the function paintEvent();

.

Problem:
Upon completion of construction, it QPainter

issues this warning:

QWidget :: paintEngine: should no longer be called

Then several other related warnings are thrown:

QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active

      

No wonder: I QPainter

didn't draw anything ...
Also, should I call paintEvent();

myself?
Or should it be called every frame QWidget

and I messed it up somehow?

I have searched the internet but all the posts I found either have no answer or they are
using something else besides QWidget

.

My code:

mfcanvas.cpp:

#include "mfcanvas.h"
#include <QDebug>
#include <QPainter>
#include <QVector2D>
#include <QList>

MFCanvas::MFCanvas(QWidget *parent) : QWidget(parent)
{
    paths = new QList<QList<QVector2D>*>();
    current = NULL;
    QWidget::resize(100, 100);
}

MFCanvas::~MFCanvas()
{
    delete paths;
}

void MFCanvas::paintEvent(QPaintEvent *)
{
    if(current!=NULL){
        if(current->length() > 1){
            QPainter painter(this);
            painter.setPen(Qt::black);
            for(int i = 1; i < current->length(); i++){
                painter.drawLine(current->at(i-1).x(), current->at(i-1).y(), current->at(i).x(), current->at(i).y());
            }
        }
    }
}

void MFCanvas::pressed(float x, float y)
{
    if(current==NULL){
        qDebug() << "null:"<<current;
        current = new QList<QVector2D>();
        current->append(QVector2D(x, y));
    }else{
        qDebug() << "current:"<<current;
    }
    paintEvent(NULL);
}

void MFCanvas::update(float x, float y)
{
    current->append(QVector2D(x, y));
}

void MFCanvas::resize(int w, int h)
{
    QWidget::resize(w, h);
}

      

main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QSurfaceFormat>
#include "creator.h"
#include "mfcanvas.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qmlRegisterType<MFCanvas>("com.cpp.mfcanvas", 1, 0, "MFCanvas");

    QQmlApplicationEngine engine;

    QQmlComponent *component = new QQmlComponent(&engine);
    QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));

    Creator creator(component);
    QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), &creator, SLOT(create(QQmlComponent::Status)));

    component->loadUrl(QUrl("qrc:///main.qml"));

    int rv;

    rv = app.exec();
    delete component;
    return rv;
}

      

creator.cpp:

#include "creator.h"
#include <QQuickWindow>
#include <QDebug>

Creator::Creator(QQmlComponent *component)
{
    this->component = component;
}

void Creator::create(QQmlComponent::Status status)
{
    if(status == QQmlComponent::Ready){
        QObject *topLevel = component->create();
        QQuickWindow::setDefaultAlphaBuffer(true);
        QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);

        QSurfaceFormat surfaceFormat = window->requestedFormat();
        window->setFormat(surfaceFormat);
        window->show();
    }
}

      

main.qml: (important part)

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import com.cpp.mfcanvas 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("MFCanvas")

    onSceneGraphInitialized: {
        drawMenu.visible = true;
        lineWidth.visible = true;
        colorMenu.visible = true;
        drawMenu.visible = false;
        lineWidth.visible = false;
        colorMenu.visible = false;
    }

    Rectangle {
        id: main
        anchors.fill: parent

        property real toolsH: 15
        property real iconW: 25

        property real menuH: 8
        property real menuW: 16

        property real dpi: (Screen.logicalPixelDensity == undefined ? 6 : Screen.logicalPixelDensity) * 1.5

        property color choosenColor: Qt.hsla(hue.value, saturation.value, luminance.value, 1)

        Text {
            anchors.centerIn: parent
            font.pointSize: 60
            text: "MFCanvas"
        }

        MFCanvas {
            id: canvas
            Component.onCompleted: {
                canvas.resize(main.width, main.height);
            }
        }
    //...
    }
}

      

Tell me if you need more information.
Thank you in advance! =

+3


source to share


3 answers


I found a simple solution:

Instead of outputting from the QWidget, output the QQuickPaintedItem. QQuickPaintedItem is a class that was created just for me: drawing on a QML element using QPainter. Here is the code (narrowed down to the essential part):
mfcanvas.h:

class MFCanvas : public QQuickPaintedItem
{
    Q_OBJECT
public:
    explicit MFCanvas(QQuickItem *parent = 0);
    ~MFCanvas();

protected:
    void paint(QPainter *painter);

      

mfcanvas.cpp:



void MFCanvas::paint(QPainter *painter)
{
    painter->translate(-translation.x(), -translation.y());
    //...
}

      

As you can see, a simple paint () function is provided that passes a pointer to the QPainter, ready to use. =)

+1


source


It is well explained here:

https://forum.qt.io/topic/64693



In short: don't try to paint directly from your input handler, but instead move the paintEvent method to your widget and create a QPainter there. Use the input event solely to change the internal data model and use the QPainter in paintEvent to render it on the output path.

+4


source


In your mfcanvas.cpp function, the void MFCanvas::pressed(float x, float y)

line

paintEvent(NULL);

      

seems unsettling. Tried this in similar code - I get the same error.

Suggested solution: Using this->repaint()

or this->update()

instead of paintEvent(NULL)

to redraw the widget seems more appropriate.

Possible explanation: looks like paintEvent () shouldn't call it simple (for example paintEvent () is called when paint () is called). As I understand from the QPainter doc, QPainter works in conjunction with QPaintDevice and QPaintEngine, these three form the basis for painting. The error QWidget::paintEngine: Should no longer be called

makes it pretty straightforward. Lines

QPainter::begin: Paint device returned engine == 0, type: 1 
QPainter::setPen: Painter not active

      

likely indicate the absence of the QPaintEngine provided by that QPaintDevice artist (for example QPaintDevice::paintEngine

). It can be assumed that this QPaintEngine was generated or otherwise called into existence by the paint device itself, for example when the paint () function is called on a widget.

+1


source







All Articles